an> - 0 jdjos/django_we_callback_settings.py
View File
@@ -0,0 +1,81 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+
4
+def DJANGO_WE_CFG_FUNC(request, state=None):
5
+    """ WeChat CFG Callback Func """
6
+
7
+
8
+def DJANGO_WE_QUOTE_STATE_FUNC(request, state):
9
+    """ WeChat Quote Callback Func """
10
+    from utils.redis.connect import r
11
+    return r.quote(state, short_uuid=True)
12
+
13
+
14
+def DJANGO_WE_UNQUOTE_STATE_FUNC(request, state):
15
+    """ WeChat UnQuote Callback Func """
16
+    from utils.redis.connect import r
17
+    # If Not Buf, When Wechat Multi Request, Unquote Will Get None
18
+    # Then Once Should ReOAuth, Will Raise Error
19
+    return r.unquote(state, buf=True) or state
20
+
21
+
22
+def DJANGO_WE_BASE_FUNC(code, state, access_info=None):
23
+    """ WeChat Base Redirect Callback Func """
24
+
25
+
26
+def DJANGO_WE_BASE_COOKIE_FUNC(code, state, access_info=None):
27
+    """ WeChat Base Set Cookie Redirect Callback Func """
28
+
29
+
30
+def DJANGO_WE_USERINFO_FUNC(code, state, access_info=None, userinfo=None):
31
+    """ WeChat Userinfo Redirect Callback Func """
32
+    from django.conf import settings
33
+    from utils.redis.connect import r
34
+    from utils.user.userinfo_save import userinfo_save
35
+
36
+    # Save profile or something else
37
+    user = userinfo_save(userinfo)
38
+
39
+    token_check_key = getattr(user, settings.TOKEN_CHECK_KEY)
40
+
41
+    return {
42
+        settings.TOKEN_CHECK_KEY: token_check_key,
43
+        'vtoken': r.token(token_check_key, ex=True, time=r.REDIS_EXPIRED_ONE_DAY, buf=False, short_uuid=True),
44
+    }
45
+
46
+
47
+def DJANGO_WE_USERINFO_COOKIE_FUNC(code, state, access_info=None, userinfo=None):
48
+    """ WeChat Userinfo Set Cookie Redirect Callback Func """
49
+    from django.conf import settings
50
+    from utils.user.userinfo_save import userinfo_save
51
+
52
+    # Save profile or something else
53
+    user = userinfo_save(userinfo)
54
+
55
+    token_check_key = getattr(user, settings.TOKEN_CHECK_KEY)
56
+
57
+    return {}, settings.TOKEN_CHECK_KEY, token_check_key
58
+
59
+
60
+def DJANGO_WE_SHARE_FUNC(request, state=None):
61
+    """ WeChat Share Callback Func """
62
+    # from django.conf import settings
63
+    # return settings.WECHAT_OAUTH2_REDIRECT_URL
64
+
65
+
66
+def DJANGO_WE_MESSAGE_CALLBACK_FUNC(request, xmldict, decrypted):
67
+    """ WeChat Message Callback Func """
68
+
69
+
70
+def DJANGO_WE_COMPONENT_AUTH_FUNC(request, xmldict, decrypted):
71
+    """ WeChat COMPONENT Auth Func """
72
+
73
+
74
+def DJANGO_WE_COMPONENT_CALLBACK_FUNC(request, appid, xmldict, decrypted):
75
+    """ WeChat COMPONENT Callback Func """
76
+
77
+
78
+def DJANGO_WE_REDIS_OBJ_FUNC(request):
79
+    """ WeChat Redis Object Callback Func """
80
+    from utils.redis.connect import r
81
+    return r

+ 16 - 0
jdjos/func_settings.py

@@ -0,0 +1,16 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+import redis_extensions as redis
4
+
5
+
6
+def redis_conf(conf):
7
+    return {
8
+        'host': conf.get('HOST', 'localhost'),
9
+        'port': conf.get('PORT', 6379),
10
+        'password': '{0}:{1}'.format(conf.get('USER', ''), conf.get('PASSWORD', '')) if conf.get('USER') else '',
11
+        'db': conf.get('db', 0),
12
+    }
13
+
14
+
15
+def redis_connect(conf):
16
+    return redis.StrictRedisExtensions(connection_pool=redis.ConnectionPool(**redis_conf(conf)))

+ 17 - 0
jdjos/local_settings_bak.py

@@ -0,0 +1,17 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+# DEBUG = False
4
+
5
+ALLOWED_HOSTS = ['127.0.0.1', 'localhost', 'jdjos']
6
+
7
+# DOMAIN
8
+DOMAIN = 'http://a.com'
9
+
10
+# 邮件设置
11
+# 只有当 DEBUG = False 的时候,才会邮件发送报错信息
12
+SERVER_EMAIL = 'error.notify@exmail.com'
13
+EMAIL_HOST_USER = 'error.notify@exmail.com'
14
+EMAIL_HOST_PASSWORD = '<^_^>pwd<^_^>'
15
+DEFAULT_FROM_EMAIL = 'error.notify <error.notify@exmail.com>'
16
+ADMINS = [('Zhang San', 'san.zhang@exmail.com'), ('Li Si', 'si.li@exmail.com')]
17
+EMAIL_SUBJECT_PREFIX = u'[Templet] '

+ 27 - 0
jdjos/local_settings_dev_bak.py

@@ -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
+]

+ 396 - 0
jdjos/settings.py

@@ -0,0 +1,396 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+"""
4
+Django settings for jdjos project.
5
+
6
+Generated by 'django-admin startproject' using Django 1.11.3.
7
+
8
+For more information on this file, see
9
+https://docs.djangoproject.com/en/1.11/topics/settings/
10
+
11
+For the full list of settings and their values, see
12
+https://docs.djangoproject.com/en/1.11/ref/settings/
13
+"""
14
+
15
+import os
16
+
17
+# try:
18
+#     from func_settings import redis_connect
19
+#     REDIS_CACHE = redis_connect(REDIS.get('default', {}))
20
+# except ImportError:
21
+#     REDIS_CACHE = None
22
+from django_redis_connector import connector
23
+
24
+
25
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
26
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
27
+PROJ_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__)))
28
+
29
+
30
+# Quick-start development settings - unsuitable for production
31
+# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
32
+
33
+# SECURITY WARNING: keep the secret key used in production secret!
34
+SECRET_KEY = '0=hpv21&am(7(k5ab!^zjvvl=ntj)^i@7)87t47uzumt_5rq$+'
35
+
36
+# SECURITY WARNING: don't run with debug turned on in production!
37
+DEBUG = True
38
+
39
+ALLOWED_HOSTS = []
40
+
41
+
42
+# Application definition
43
+
44
+INSTALLED_APPS = [
45
+    'django.contrib.admin',
46
+    'django.contrib.auth',
47
+    'django.contrib.contenttypes',
48
+    'django.contrib.sessions',
49
+    'django.contrib.messages',
50
+    'django.contrib.staticfiles',
51
+    # 'django_file_upload',
52
+    # 'django_short_url',
53
+    'django_uniapi',
54
+    'django_admin',
55
+    'django_we',
56
+    'commands',
57
+    'api',
58
+]
59
+
60
+MIDDLEWARE = [
61
+    'django.middleware.security.SecurityMiddleware',
62
+    'django.contrib.sessions.middleware.SessionMiddleware',
63
+    'django.middleware.common.CommonMiddleware',
64
+    # 'django.middleware.csrf.CsrfViewMiddleware',
65
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
66
+    'django.contrib.messages.middleware.MessageMiddleware',
67
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
68
+    'detect.middleware.UserAgentDetectionMiddleware',
69
+]
70
+
71
+ROOT_URLCONF = 'jdjos.urls'
72
+
73
+TEMPLATES = [
74
+    {
75
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
76
+        'DIRS': [os.path.join(BASE_DIR, 'templates')],
77
+        # 'APP_DIRS': True,
78
+        'OPTIONS': {
79
+            'context_processors': [
80
+                'django.template.context_processors.debug',
81
+                'django.template.context_processors.request',
82
+                'django.contrib.auth.context_processors.auth',
83
+                'django.contrib.messages.context_processors.messages',
84
+            ],
85
+            'loaders': [
86
+                ('django.template.loaders.cached.Loader', [
87
+                    'django.template.loaders.filesystem.Loader',
88
+                    'django.template.loaders.app_directories.Loader',
89
+                ]),
90
+            ],
91
+        },
92
+    },
93
+]
94
+
95
+WSGI_APPLICATION = 'jdjos.wsgi.application'
96
+
97
+
98
+# Database9
99
+# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
100
+
101
+DATABASES = {
102
+    # Create Database
103
+    # CREATE DATABASE jdjos DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
104
+    'default': {
105
+        'ENGINE': 'django.db.backends.mysql',
106
+        'NAME': 'jdjos',
107
+        'USER': 'root',
108
+        'PASSWORD': '',
109
+        'HOST': '127.0.0.1',
110
+        'PORT': 3306,
111
+        'CONN_MAX_AGE': 600,
112
+        'OPTIONS': {
113
+            # Utf8mb4 for Emoji
114
+            #
115
+            # Nickname
116
+            #
117
+            # account.WechatInfo ==> nickname
118
+            #   ALTER TABLE account_wechatinfo MODIFY COLUMN nickname VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
119
+            'charset': 'utf8mb4',
120
+        },
121
+    }
122
+}
123
+
124
+
125
+# Password validation
126
+# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
127
+
128
+AUTH_PASSWORD_VALIDATORS = [
129
+    {
130
+        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
131
+    },
132
+    {
133
+        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
134
+    },
135
+    {
136
+        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
137
+    },
138
+    {
139
+        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
140
+    },
141
+]
142
+
143
+
144
+# Internationalization
145
+# https://docs.djangoproject.com/en/1.11/topics/i18n/
146
+
147
+LANGUAGE_CODE = 'zh-Hans'
148
+
149
+TIME_ZONE = 'Asia/Shanghai'
150
+
151
+USE_I18N = True
152
+
153
+USE_L10N = True
154
+
155
+USE_TZ = True
156
+
157
+
158
+# Static files (CSS, JavaScript, Images)
159
+# https://docs.djangoproject.com/en/1.11/howto/static-files/
160
+
161
+STATICFILES_DIRS = (
162
+    os.path.join(PROJ_DIR, 'static').replace('\\', '/'),
163
+)
164
+
165
+STATIC_ROOT = os.path.join(BASE_DIR, 'collect_static').replace('\\', '/')
166
+
167
+STATIC_URL = '/static/'
168
+
169
+STATICFILES_FINDERS = (
170
+    'django.contrib.staticfiles.finders.FileSystemFinder',
171
+    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
172
+    # 'django.contrib.staticfiles.finders.DefaultStorageFinder',
173
+)
174
+
175
+MEDIA_ROOT = os.path.join(BASE_DIR, 'media').replace('\\', '/')
176
+
177
+MEDIA_URL = '/media/'
178
+
179
+# File 设置
180
+FILE_UPLOAD_MAX_MEMORY_SIZE = 5242880  # InMemoryUploadedFile 文件最大值,设置为 5 MB
181
+FILE_UPLOAD_PERMISSIONS = 0o644  # TemporaryUploadedFile 文件权限设置
182
+
183
+# DOMAIN
184
+DOMAIN = 'http://a.com'
185
+
186
+# Redis 设置
187
+REDIS = {
188
+    'default': {
189
+        'HOST': '127.0.0.1',
190
+        'PORT': 6379,
191
+        'USER': '',
192
+        'PASSWORD': '',
193
+        'db': 0,
194
+    }
195
+}
196
+
197
+# 微信设置
198
+WECHAT = {
199
+    'JSAPI': {
200
+        'trade_type': 'JSAPI',  # JSAPI-网页支付、Native-原生支付、APP-APP支付、MICROPAY-刷卡支付
201
+        'token': '5201314',
202
+        'appID': '',
203
+        'appsecret': '',
204
+        'encodingaeskey': '',
205
+        'mchID': '',
206
+        'apiKey': '',
207
+        'mch_cert': '',
208
+        'mch_key': '',
209
+        'redpack': {
210
+
211
+        }
212
+    },
213
+}
214
+
215
+WECHAT_DEFAULT_CFG = 'JSAPI'
216
+
217
+# 微信唯一标识
218
+# Choices: 'unionid' or 'openid'
219
+#
220
+# models.py
221
+#   'unique_identifier': self.unionid if settings.WECHAT_UNIQUE_IDENTIFICATION == 'unionid' else self.openid,
222
+# views.py
223
+#   unique_identifier = request.POST.get(settings.WECHAT_UNIQUE_IDENTIFICATION, '')
224
+#   profile = Profile.objects.get(**{settings.WECHAT_UNIQUE_IDENTIFICATION: unique_identifier})
225
+#
226
+# If not bind to OpenPlat, change `WECHAT_UNIQUE_IDENTIFICATION` as `openid`
227
+WECHAT_UNIQUE_IDENTIFICATION = 'unionid'
228
+
229
+# Token 错误重授权设置
230
+TOKEN_CHECK_KEY = ''
231
+# TOKEN_CHECK_KEY = 'user_id'
232
+WECHAT_OAUTH2_REDIRECT_ENTRY = ''
233
+WECHAT_OAUTH2_REDIRECT_URL = ''
234
+
235
+# Cookie 设置
236
+DJANGO_WE_COOKIE_MAX_AGE = COOKIE_MAX_AGE = 31536000  # 单位:秒,1年:365 * 24 * 60 * 60 = 31536000
237
+DJANGO_WE_COOKIE_SALT = COOKIE_SALT = 'djwe'  # Salt for ``set_signed_cookie``
238
+# Cookie 校验设置
239
+COOKIE_USER_CHECK_KEY = ''
240
+# COOKIE_USER_CHECK_KEY = 'user_id'
241
+
242
+# 邮件设置
243
+# https://docs.djangoproject.com/en/1.11/howto/error-reporting/#email-reports
244
+# When DEBUG is False, Django will email the users listed in the ADMINS setting
245
+# whenever your code raises an unhandled exception and results in an internal server error (HTTP status code 500).
246
+# 只有当 DEBUG = False 的时候,才会邮件发送报错信息
247
+# Email address that error messages come from.
248
+SERVER_EMAIL = 'error.notify@exmail.com'
249
+# The email backend to use. For possible shortcuts see django.core.mail.
250
+# The default is to use the SMTP backend.
251
+# Third-party backends can be specified by providing a Python path
252
+# to a module that defines an EmailBackend class.
253
+EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
254
+# Host for sending email.
255
+EMAIL_HOST = 'smtp.exmail.qq.com'
256
+# Port for sending email.
257
+EMAIL_PORT = 25
258
+# Optional SMTP authentication information for EMAIL_HOST.
259
+EMAIL_HOST_USER = 'error.notify@exmail.com'
260
+EMAIL_HOST_PASSWORD = '<^_^>pwd<^_^>'
261
+EMAIL_USE_TLS = False
262
+EMAIL_USE_SSL = False
263
+EMAIL_SSL_CERTFILE = None
264
+EMAIL_SSL_KEYFILE = None
265
+EMAIL_TIMEOUT = None
266
+# Default email address to use for various automated correspondence from
267
+# the site managers.
268
+DEFAULT_FROM_EMAIL = 'error.notify <error.notify@exmail.com>'
269
+# People who get code error notifications.
270
+# In the format [('Full Name', 'email@example.com'), ('Full Name', 'anotheremail@example.com')]
271
+ADMINS = [('Zhang San', 'san.zhang@exmail.com'), ('Li Si', 'si.li@exmail.com')]
272
+# Not-necessarily-technical managers of the site. They get broken link
273
+# notifications and other various emails.
274
+MANAGERS = ADMINS
275
+# Subject-line prefix for email messages send with django.core.mail.mail_admins
276
+# or ...mail_managers.  Make sure to include the trailing space.
277
+EMAIL_SUBJECT_PREFIX = u'[Templet] '
278
+
279
+# Django-Admin Settings
280
+DJANGO_ADMIN_DISABLE_DELETE_SELECTED = False
281
+
282
+# Django-FILE-UPLOAD Settings
283
+DJANGO_FILE_UPLOAD_USE_YM = True
284
+DJANGO_FILE_UPLOAD_USE_DT = True
285
+
286
+# Django-Logit Settings
287
+DJANGO_LOGIT_ENABLED = True
288
+DJANGO_LOGIT_BODY_FLAG = False
289
+DJANGO_LOGIT_RES_FLAG = False
290
+
291
+# Django-Onerror Settings
292
+DJANGO_ONERROR_ACCEPT_REPORT = True
293
+DJANGO_ONERROR_ADMIN_SITE_REGISTER = True
294
+
295
+# Django-Short-URL Settings
296
+# Redirect url when short url not exists
297
+DJANGO_SHORT_URL_REDIRECT_URL = ''
298
+
299
+# Django-We Settings
300
+DJANGO_WE_QUOTE_OR_NOT = True
301
+# Enable Cookie or not
302
+# DJANGO_WE_BASE_REDIRECT_SET_COOKIE = False
303
+# DJANGO_WE_USERINFO_REDIRECT_SET_COOKIE = True
304
+# Cookie Config
305
+DJANGO_WE_COOKIE_MAX_AGE = COOKIE_MAX_AGE
306
+DJANGO_WE_COOKIE_SALT = COOKIE_SALT
307
+
308
+# 开发调试相关配置
309
+if DEBUG:
310
+    try:
311
+        from local_settings_dev import *
312
+    except ImportError:
313
+        pass
314
+
315
+try:
316
+    from local_settings import *
317
+except ImportError:
318
+    pass
319
+
320
+try:
321
+    from django_file_callback_settings import *
322
+except ImportError:
323
+    pass
324
+
325
+try:
326
+    from django_we_callback_settings import *
327
+except ImportError:
328
+    pass
329
+
330
+# 依赖 local_settings 中的配置
331
+# 微信授权设置
332
+# WECHAT_OAUTH2_REDIRECT_URI = '{0}/we/oauth2?scope={{0}}&redirect_url={{1}}'.format(DOMAIN)
333
+# Shorten URL
334
+# ``o`` is short for oauth2
335
+# ``r`` is short for redirect_url
336
+WECHAT_OAUTH2_REDIRECT_URI = '{0}/we/o?scope={{0}}&r={{1}}'.format(DOMAIN)
337
+WECHAT_OAUTH2_USERINFO_REDIRECT_URI = '{0}/we/o?r={{0}}'.format(DOMAIN)  # Scope default snsapi_userinfo
338
+WECHAT_BASE_REDIRECT_URI = '{0}/we/base_redirect'.format(DOMAIN)
339
+WECHAT_USERINFO_REDIRECT_URI = '{0}/we/userinfo_redirect'.format(DOMAIN)
340
+WECHAT_DIRECT_BASE_REDIRECT_URI = '{0}/we/direct_base_redirect'.format(DOMAIN)
341
+WECHAT_DIRECT_USERINFO_REDIRECT_URI = '{0}/we/direct_userinfo_redirect'.format(DOMAIN)
342
+
343
+JDJOS_OAUTH_AUTHORIZE = 'https://oauth.jd.com/oauth/authorize?response_type=code&client_id={client_id}&redirect_uri={redirect_uri}&state={state}'
344
+JDJOS_OAUTH_TOKEN = 'https://oauth.jd.com/oauth/token?grant_type=authorization_code&client_id={client_id}&redirect_uri={redirect_uri}&code={code}&state={state}&client_secret={client_secret}'
345
+JDJOS_REDIRECT_URI = '{0}/jos/oauth'.format(DOMAIN)
346
+
347
+# Redis 连接
348
+WECHAT_REDIS_OBJ = REDIS_CACHE = connector(REDIS.get('default', {}))
349
+
350
+# LOGGER 设置
351
+# python manage.py rlistlog --key=django:logit:jdjos --filename=/tmp/jdjos.logit.log
352
+LOGGING = {
353
+    'version': 1,
354
+    'disable_existing_loggers': False,
355
+    'formatters': {
356
+        'verbose': {
357
+            'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
358
+        },
359
+        'simple': {
360
+            'format': '%(levelname)s %(message)s'
361
+        },
362
+    },
363
+    'handlers': {
364
+        'logit': {
365
+            'level': 'DEBUG',
366
+            'class': 'rlog.RedisListHandler',
367
+            'redis_client': REDIS_CACHE,
368
+            'key': 'django:logit:jdjos',
369
+            'formatter': 'verbose',
370
+        },
371
+        'console': {
372
+            'level': 'DEBUG',
373
+            'class': 'logging.StreamHandler',
374
+            'formatter': 'verbose'
375
+        },
376
+    },
377
+    'loggers': {
378
+        'logit': {
379
+            'handlers': ['logit'],
380
+            'level': 'DEBUG',
381
+            'propagate': True,
382
+        },
383
+        'console': {
384
+            'handlers': ['console'],
385
+            'level': 'DEBUG',
386
+            'propagate': True,
387
+        },
388
+    },
389
+}
390
+
391
+# MAX_BIGINT
392
+# Why Not ``sys.maxint``
393
+# n bit platform sys.maxint = 2 ** (n - 1) - 1
394
+# 64 bit 9223372036854775807, 32 bit 2147483647
395
+from django.db.models import BigIntegerField  # isort:skip
396
+MAX_BIGINT = BigIntegerField.MAX_BIGINT

+ 68 - 0
jdjos/static/jdjos/css/common.css

@@ -0,0 +1,68 @@
1
+.text-center {
2
+    text-align: center;
3
+}
4
+
5
+/*
6
+  文本溢出省略,元素需要设置定宽度
7
+  */
8
+/* 单行 */
9
+.text_ellipsis {
10
+    overflow: hidden;
11
+    white-space: nowrap;
12
+    text-overflow: ellipsis;
13
+}
14
+/* 多行 */
15
+.a {
16
+    overflow: hidden;
17
+    text-overflow: ellipsis;
18
+    display: -webkit-box;
19
+    -webkit-line-clamp: 2;
20
+    -webkit-box-orient: vertical;
21
+}
22
+
23
+/*
24
+  浮动 & 清除浮动
25
+ */
26
+.fl {
27
+    float: left;
28
+}
29
+
30
+.fr {
31
+    float: right;
32
+}
33
+
34
+.clearfix {
35
+    zoom: 1;
36
+}
37
+
38
+.clearfix:after {
39
+    content: "\200B";
40
+    display: block;
41
+    height: 0;
42
+    clear: both;
43
+}
44
+
45
+.clearfix:after {content:"."; display:block; height:0; visibility:hidden; clear:both; }
46
+.clearfix { *zoom:1; }
47
+
48
+/*
49
+  解决安卓微信点击图片预览问题
50
+  这个会让 img 标签的点击事件失效,如果想要点击图片就要给上面再写一层
51
+  需要长按识别二维码的时候,则再单独给该图片添加
52
+  ```css
53
+  pointer-events: auto;
54
+  ```
55
+  来恢复对应的点击事件
56
+  */
57
+img {
58
+    pointer-events: none;
59
+}
60
+
61
+.clickable {
62
+    pointer-events: auto;
63
+}
64
+
65
+/* Input 自动填充后,移除 Chrome 默认黄色 */
66
+input:-webkit-autofill {
67
+    box-shadow: 0 0 0 1000px white inset !important;
68
+}

+ 574 - 0
jdjos/static/jdjos/js/jswe.js

@@ -0,0 +1,574 @@
1
+!(function(e, t) {
2
+    var config = {
3
+        wxconfig: 'http://api.tt4it.com/wx/jsapi_signature',
4
+        callback: 'callback'
5
+    }, wxData = {
6
+        debug: false,
7
+        imgUrl: '',
8
+        link: '',
9
+        desc: '',
10
+        title: '',
11
+        timeLine: ''
12
+    }, wxConfig = {
13
+        hide: false,
14
+        baseFlag: false,
15
+        baseHide: false,
16
+        close: false,
17
+        hideMenuItems: [],
18
+        showMenuItems: []
19
+    }, jsApiList = [
20
+        'checkJsApi',
21
+        'onMenuShareTimeline',
22
+        'onMenuShareAppMessage',
23
+        'onMenuShareQQ',
24
+        'onMenuShareWeibo',
25
+        'onMenuShareQZone',
26
+        'hideMenuItems',
27
+        'showMenuItems',
28
+        'hideAllNonBaseMenuItem',
29
+        'showAllNonBaseMenuItem',
30
+        'translateVoice',
31
+        'startRecord',
32
+        'stopRecord',
33
+        'onRecordEnd',
34
+        'playVoice',
35
+        'pauseVoice',
36
+        'stopVoice',
37
+        'uploadVoice',
38
+        'downloadVoice',
39
+        'chooseImage',
40
+        'previewImage',
41
+        'uploadImage',
42
+        'downloadImage',
43
+        'getLocalImgData',
44
+        'getNetworkType',
45
+        'openLocation',
46
+        'getLocation',
47
+        'hideOptionMenu',
48
+        'showOptionMenu',
49
+        'closeWindow',
50
+        'scanQRCode',
51
+        'chooseWXPay',
52
+        'openEnterpriseRedPacket',
53
+        'openProductSpecificView',
54
+        'addCard',
55
+        'chooseCard',
56
+        'openCard'
57
+    ], wxApiFun
58
+
59
+    function isEmpty(obj) {
60
+        if (obj == null) return true
61
+        if (obj.length > 0) return false
62
+        if (obj.length === 0) return true
63
+        for (var key in obj) {
64
+            if (Object.prototype.hasOwnProperty.call(obj, key)) return false
65
+        }
66
+        return true
67
+    }
68
+
69
+    function isNotEmpty(obj) {
70
+        return !isEmpty(obj)
71
+    }
72
+
73
+    function isOpenOnPC() {  // 判断当前网页是否在 PC 浏览器中打开
74
+        var ua = navigator.userAgent
75
+        return /windows nt/i.test(ua) || /macintosh/i.test(ua) || /linux x86_64/i.test(ua)
76
+    }
77
+
78
+    function isOpenInWeixin() {  // 判断当前网页是否在微信内置浏览器中打开
79
+        return /micromessenger/i.test(navigator.userAgent)
80
+    }
81
+
82
+    function getWeixinVersion() {
83
+        var ua = navigator.userAgent,
84
+            mt = ua.match(/micromessenger\/([\d.]+)/i)
85
+        return (mt ? mt[1] : '')
86
+    }
87
+
88
+    // This function checks whether Wechat is the appointed version or not
89
+    // Cmp: http://jsperf.com/regexp-test-vs-indexof-ignore-upper-and-lower
90
+    function isWeixinVersion(version) {
91
+        // return new RegExp('micromessenger/' + version , 'i').test(navigator.userAgent)
92
+        return navigator.userAgent.toLowerCase().indexOf('micromessenger/' + version) != -1
93
+    }
94
+
95
+    function hideOptionMenu() {
96
+        wxConfig.hide = true
97
+        fixedWxData()
98
+    }
99
+
100
+    function showOptionMenu() {
101
+        wxConfig.hide = false
102
+        fixedWxData()
103
+    }
104
+
105
+    function hideMenuItems(items) {
106
+        wxConfig.hideMenuItems = items
107
+        fixedWxData()
108
+    }
109
+
110
+    function showMenuItems(items) {
111
+        wxConfig.showMenuItems = items
112
+        fixedWxData()
113
+    }
114
+
115
+    function hideAllNonBaseMenuItem() {
116
+        wxConfig.baseFlag = true
117
+        wxConfig.baseHide = true
118
+        fixedWxData()
119
+    }
120
+
121
+    function showAllNonBaseMenuItem() {
122
+        wxConfig.baseFlag = true
123
+        wxConfig.baseHide = false
124
+        fixedWxData()
125
+    }
126
+
127
+    function closeWindow() {
128
+        wxConfig.close = true
129
+        fixedWxData()
130
+    }
131
+
132
+    function wxReady(data) {
133
+        data = typeof data === 'object' ? data : JSON.parse(data)
134
+        wx.config({
135
+            debug: wxData.debug,
136
+            appId: data.appId,
137
+            timestamp: data.timestamp,
138
+            nonceStr: data.nonceStr,
139
+            signature: data.signature,
140
+            jsApiList: jsApiList
141
+        })
142
+
143
+        var callbacks = {
144
+            trigger: function (res) {
145
+                // alert('用户点击发送给朋友')
146
+                if (JSWE.wxTrigger) {JSWE.wxTrigger(res)}
147
+            },
148
+            success: function (res) {
149
+                // alert('已分享')
150
+                if (JSWE.wxSuccess) {JSWE.wxSuccess(res)}
151
+            },
152
+            cancel: function (res) {
153
+                // alert('已取消')
154
+                if (JSWE.wxCancel) {JSWE.wxCancel(res)}
155
+            },
156
+            fail: function (res) {
157
+                // alert(JSON.stringify(res))
158
+                if (JSWE.wxFail) {JSWE.wxFail(res)}
159
+            }
160
+        }, shareInfo = function(flag) {
161
+            var _share = {
162
+                title: flag ? wxData.title : (wxData.timeLine || wxData.desc),
163
+                link: wxData.link,
164
+                imgUrl: wxData.imgUrl,
165
+                trigger: callbacks.trigger,
166
+                success: callbacks.success,
167
+                cancel: callbacks.cancel,
168
+                fail: callbacks.fail
169
+            }
170
+            if (flag) _share.desc = wxData.desc
171
+            return _share
172
+        }, wxShareApi = function() {
173
+            // 2. 分享接口
174
+            // 2.1 监听“分享给朋友”,按钮点击、自定义分享内容及分享结果接口
175
+            wx.onMenuShareAppMessage(shareInfo(1))
176
+            // 2.2 监听“分享到朋友圈”按钮点击、自定义分享内容及分享结果接口
177
+            wx.onMenuShareTimeline(shareInfo(0))
178
+            // 2.3 监听“分享到QQ”按钮点击、自定义分享内容及分享结果接口
179
+            wx.onMenuShareQQ(shareInfo(1))
180
+            // 2.4 监听“分享到微博”按钮点击、自定义分享内容及分享结果接口
181
+            wx.onMenuShareWeibo(shareInfo(1))
182
+            // 2.5 监听“分享到QQ空间”按钮点击、自定义分享内容及分享结果接口
183
+            wx.onMenuShareQZone(shareInfo(1))
184
+        }, wxMenuApi = function () {
185
+            // 8. 界面操作接口
186
+            // 8.1 隐藏右上角菜单
187
+            // 8.2 显示右上角菜单
188
+            if (wxConfig.hide) {wx.hideOptionMenu()} else {wx.showOptionMenu()}
189
+            // 8.3 批量隐藏菜单项
190
+            if (isNotEmpty(wxConfig.hideMenuItems)) {
191
+                wx.hideMenuItems({
192
+                    menuList: wxConfig.hideMenuItems,
193
+                    success: function (res) {
194
+                        if (JSWE.wxHideMenuItemsSuccess) {JSWE.wxHideMenuItemsSuccess(res)}
195
+                    },
196
+                    fail: function (res) {
197
+                        if (JSWE.wxHideMenuItemsFail) {JSWE.wxHideMenuItemsFail(res)}
198
+                    }
199
+                })
200
+            }
201
+            // 8.4 批量显示菜单项
202
+            if (isNotEmpty(wxConfig.showMenuItems)) {
203
+                wx.showMenuItems({
204
+                    menuList: wxConfig.showMenuItems,
205
+                    success: function (res) {
206
+                        if (JSWE.wxShowMenuItemsSuccess) {JSWE.wxShowMenuItemsSuccess(res)}
207
+                    },
208
+                    fail: function (res) {
209
+                        if (JSWE.wxShowMenuItemsFail) {JSWE.wxShowMenuItemsFail(res)}
210
+                    }
211
+                })
212
+            }
213
+            // 8.5 隐藏所有非基本菜单项
214
+            // 8.6 显示所有被隐藏的非基本菜单项
215
+            if (wxConfig.baseFlag) {
216
+                if (wxConfig.baseHide) {wx.hideAllNonBaseMenuItem()} else {wx.showAllNonBaseMenuItem()}
217
+            }
218
+            // 8.7 关闭当前窗口
219
+            if (wxConfig.close) {wx.closeWindow()}
220
+        }, wxVoiceApi = function() {
221
+            // 4.3 监听录音自动停止
222
+            wx.onVoiceRecordEnd({
223
+                complete: function (res) {
224
+                    voice.localId = res.localId
225
+                    if (JSWE.wxVoiceRecordEnd) {JSWE.wxVoiceRecordEnd(res)}
226
+                }
227
+            })
228
+            // 4.7 监听录音播放停止
229
+            wx.onVoicePlayEnd({
230
+                complete: function (res) {
231
+                    if (JSWE.wxVoicePlayEnd) {JSWE.wxVoicePlayEnd(res)}
232
+                }
233
+            })
234
+        }, wxApi = function () {
235
+            wxShareApi()
236
+            wxMenuApi()
237
+            wxVoiceApi()
238
+        }
239
+
240
+        wx.ready(wxApi)
241
+
242
+        return wxApiFun = wxApi
243
+    }
244
+
245
+    if (isOpenInWeixin() || isOpenOnPC()) {
246
+        if ('undefined' !== typeof JSWE_CONF_UPDATE) JSWE_CONF_UPDATE(config)
247
+        $.ajax({
248
+            url: config.wxconfig,
249
+            type: 'get',
250
+            dataType: 'jsonp',
251
+            jsonpCallback: config.callback,
252
+            data: {
253
+                url: window.location.href.split('#')[0]
254
+            },
255
+            success: wxReady
256
+        })
257
+    }
258
+
259
+    function initWxData(data, flag) {
260
+        for(var d in data) {if (d in wxData) wxData[d] = data[d]}
261
+        if (flag) fixedWxData()
262
+    }
263
+
264
+    function changeWxData(key, value, flag) {
265
+        if (key in falDwxDataata) {wxData[key] = value}
266
+        if (flag) fixedWxData()
267
+    }
268
+
269
+    function fixedWxData() {
270
+        if ('undefined' !== typeof wxApiFun) wxApiFun()
271
+    }
272
+
273
+    // 3 智能接口
274
+    var voice = {
275
+        localId: '',
276
+        serverId: ''
277
+    }
278
+    // 3.1 识别音频并返回识别结果
279
+    function translateVoice() {
280
+        if (voice.localId == '') {
281
+            if (JSWE.wxTranslateVoiceEmpty) {JSWE.wxTranslateVoiceEmpty()}
282
+            return
283
+        }
284
+        wx.translateVoice({
285
+            localId: voice.localId,
286
+            complete: function (res) {
287
+                if (JSWE.wxTranslateVoiceComplete) {JSWE.wxTranslateVoiceComplete(res)}
288
+            }
289
+        })
290
+    }
291
+
292
+    // 4 音频接口
293
+    // 4.1 开始录音
294
+    function startRecord() {
295
+        wx.startRecord({
296
+            cancel: function () {
297
+                if (JSWE.wxStartRecordCancel) {JSWE.wxStartRecordCancel(res)}
298
+            }
299
+        })
300
+    }
301
+
302
+    // 4.2 停止录音
303
+    function stopRecord() {
304
+        wx.stopRecord({
305
+          success: function (res) {
306
+              voice.localId = res.localId
307
+              if (JSWE.wxStopRecordSuccess) {JSWE.wxStopRecordSuccess(res)}
308
+          },
309
+          fail: function (res) {
310
+              if (JSWE.wxStopRecordFail) {JSWE.wxStopRecordFail(res)}
311
+          }
312
+        })
313
+    }
314
+
315
+    // 4.4 播放音频
316
+    function playVoice() {
317
+        if (voice.localId == '') {
318
+            if (JSWE.wxPlayVoiceEmpty) {JSWE.wxPlayVoiceEmpty()}
319
+            return
320
+        }
321
+        wx.playVoice({
322
+            localId: voice.localId
323
+        })
324
+    }
325
+
326
+    // 4.5 暂停播放音频
327
+    function pauseVoice() {
328
+        if (voice.localId == '') {
329
+            if (JSWE.wxPauseVoiceEmpty) {JSWE.wxPauseVoiceEmpty()}
330
+            return
331
+        }
332
+        wx.pauseVoice({
333
+            localId: voice.localId
334
+        })
335
+    }
336
+
337
+    // 4.6 停止播放音频
338
+    function stopVoice() {
339
+        if (voice.localId == '') {
340
+            if (JSWE.wxStopVoiceEmpty) {JSWE.wxStopVoiceEmpty()}
341
+            return
342
+        }
343
+        wx.stopVoice({
344
+            localId: voice.localId
345
+        })
346
+    }
347
+
348
+    // 4.8 上传语音
349
+    function uploadVoice() {
350
+        var localId = voice.localId
351
+        if (localId == '') {
352
+            if (JSWE.wxUploadVoiceEmpty) {JSWE.wxUploadVoiceEmpty()}
353
+            return
354
+        }
355
+        wx.uploadVoice({
356
+            localId: localId,
357
+            success: function (res) {
358
+                voice.serverId = res.serverId
359
+                if (JSWE.wxUploadVoiceSuccess) {JSWE.wxUploadVoiceSuccess(res, localId)}
360
+            }
361
+        })
362
+    }
363
+
364
+    // 4.9 下载语音
365
+    function downloadVoice() {
366
+        var serverId = voice.serverId
367
+        if (serverId == '') {
368
+            if (JSWE.wxDownloadVoiceEmpty) {JSWE.wxDownloadVoiceEmpty()}
369
+            return
370
+        }
371
+        wx.downloadVoice({
372
+            serverId: serverId,
373
+            success: function (res) {
374
+                voice.localId = res.localId
375
+                if (JSWE.wxDownloadVoiceSuccess) {JSWE.wxDownloadVoiceSuccess(res, serverId)}
376
+            }
377
+        })
378
+    }
379
+
380
+    // 5 图片接口
381
+    var images = {
382
+        localIds: [],
383
+        serverIds: []
384
+    }
385
+    // 5.1 拍照、本地选图
386
+    function chooseImage(choose_params) {
387
+        if ('undefined' === typeof choose_params) choose_params = {}
388
+        wx.chooseImage({
389
+            count: choose_params.count || 9, // 默认9
390
+            sizeType: choose_params.sizeType || ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
391
+            sourceType: choose_params.sourceType || ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
392
+            success: function (res) {
393
+                images.localIds = res.localIds // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片
394
+                // 判断是否直接上传
395
+                if (choose_params.directUpload) {setTimeout(uploadImages({localIds: images.localIds, isShowProgressTips: choose_params.isShowProgressTips || 1}), 100)}
396
+                // 拍照、本地选图成功后的回调函数
397
+                if (JSWE.wxChooseImageSuccess) {JSWE.wxChooseImageSuccess(res, choose_params.extras || {})}
398
+            }
399
+        })
400
+    }
401
+
402
+    // 5.2 图片预览
403
+    function previewImage(preview_params) {
404
+        wx.previewImage({
405
+            current: preview_params.current, // 当前显示图片的链接,不填则默认为 urls 的第一张
406
+            urls: preview_params.urls // 需要预览的图片链接列表
407
+        })
408
+    }
409
+
410
+    // 5.3 上传图片
411
+    function uploadImage(upload_params) {
412
+        // 上传图片为异步处理,重复上传同一图片,返回的serverId也是不同的
413
+        var localId = upload_params.localId
414
+        wx.uploadImage({
415
+            localId: localId, // 需要上传的图片的本地ID,由chooseImage接口获得
416
+            isShowProgressTips: upload_params.isShowProgressTips || 1, // 默认为1,显示进度提示
417
+            success: function (res) {
418
+                images.serverIds.push(res.serverId) // 返回图片的服务器端ID
419
+                // 上传图片成功后的回调函数
420
+                if (JSWE.wxUploadImageSuccess) {JSWE.wxUploadImageSuccess(res, localId)}
421
+            }
422
+        })
423
+    }
424
+
425
+    function uploadImages(upload_params) {
426
+        var localIds = upload_params.localIds, isShowProgressTips = upload_params.isShowProgressTips || 1
427
+        images.serverIds = []
428
+        for (var idx in localIds) {uploadImage({localId: localIds[idx], isShowProgressTips: isShowProgressTips})}
429
+    }
430
+
431
+    // 5.4 下载图片
432
+    function downloadImage(download_params) {
433
+        var serverId = download_params.serverId
434
+        wx.downloadImage({
435
+            serverId: serverId, // 需要下载的图片的服务器端ID,由uploadImage接口获得
436
+            isShowProgressTips: download_params.isShowProgressTips || 1, // 默认为1,显示进度提示
437
+            success: function (res) {
438
+                images.localId.push(res.localId)
439
+                if (JSWE.wxDownloadImageSuccess) {JSWE.wxDownloadImageSuccess(res, serverId)}
440
+            }
441
+        })
442
+    }
443
+
444
+    function downloadImages(download_params) {
445
+        var serverIds = download_params.serverIds, isShowProgressTips = download_params.isShowProgressTips || 1
446
+        images.localIds = []
447
+        for (var idx in serverIds) {downloadImage({serverId: serverIds[idx], isShowProgressTips: isShowProgressTips})}
448
+    }
449
+
450
+    function getLocalImgData(localId) {
451
+        wx.getLocalImgData({
452
+            localId: localId, // 图片的localID
453
+            success: function (res) {
454
+                // var localData = res.localData; // localData是图片的base64数据,可以用img标签显示
455
+                if (JSWE.wxGetLocalImgDataSuccess) {JSWE.wxGetLocalImgDataSuccess(res)}
456
+            }
457
+        })
458
+    }
459
+
460
+    // 9 微信原生接口
461
+    // 9.1.1 扫描二维码并返回结果
462
+    // 9.1.2 扫描二维码并返回结果
463
+    function scanQRCode(scan_params) {
464
+        if ('undefined' === typeof scan_params) scan_params = {}
465
+        wx.scanQRCode({
466
+            needResult: scan_params.needResult || 0,  // 默认为0,0扫描结果由微信处理,1直接返回扫描结果
467
+            scanType: scan_params.scanType || ['qrCode', 'barCode'],  // 可以指定扫二维码还是一维码,默认二者都有
468
+            success: function (res) {  // 当 needResult 为 1 时,扫码返回的结果
469
+                if (JSWE.wxScanQRCodeSuccess) {JSWE.wxScanQRCodeSuccess(res)}
470
+            }
471
+        })
472
+    }
473
+
474
+    // QRCode & BarCode is different
475
+    function parseScanQRCodeResultStr(resultStr) {
476
+        var strs = resultStr.split(',')
477
+        return strs[strs.length - 1]
478
+    }
479
+
480
+    // 10 微信支付接口
481
+    // 10.1 发起一个支付请求
482
+    function chooseWXPay(wxpay_params) {
483
+        wx.chooseWXPay({
484
+            timestamp: wxpay_params.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
485
+            nonceStr: wxpay_params.nonceStr, // 支付签名随机串,不长于 32 位
486
+            package: wxpay_params.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
487
+            signType: wxpay_params.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
488
+            paySign: wxpay_params.paySign, // 支付签名
489
+            success: function (res) {
490
+                // 支付成功后的回调函数
491
+                if (JSWE.wxPaySuccess) {JSWE.wxPaySuccess(res)}
492
+            }
493
+        })
494
+    }
495
+
496
+    // xx 微信原生企业红包接口
497
+    // xx.1 发起一个发送原生企业红包请求
498
+    function openEnterpriseRedPacket(wxredpack_params) {
499
+        wx.openEnterpriseRedPacket({
500
+            timeStamp: wxredpack_params.timeStamp, // 红包签名时间戳,注意原生企业红包接口timeStamp字段名需大写其中的S字符,而支付接口timeStamp字段名无需大写其中的S字符。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
501
+            nonceStr: wxredpack_params.nonceStr, // 红包签名随机串,不长于 32 位
502
+            package: encodeURIComponent(wxredpack_params.package), // 发放红包接口返回的prepay_id参数值,提交格式如:prepay_id=***)
503
+            signType: wxredpack_params.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
504
+            paySign: wxredpack_params.paySign, // 红包签名
505
+            success: function (res) {
506
+                // 发送原生企业红包成功后的回调函数
507
+                if (JSWE.wxEnterpriseRedPacketSuccess) {JSWE.wxEnterpriseRedPacketSuccess(res)}
508
+            }
509
+        })
510
+    }
511
+
512
+    var v = {
513
+        version: '1.0.5',
514
+
515
+        // Basic Vars
516
+        config: config,
517
+        wxData: wxData,
518
+        jsApiList: jsApiList,
519
+
520
+        isEmpty: isEmpty,
521
+        isNotEmpty: isNotEmpty,
522
+
523
+        // Weixin Function
524
+        isOpenInWeixin: isOpenInWeixin,
525
+        getWeixinVersion: getWeixinVersion,
526
+        isWeixinVersion: isWeixinVersion,
527
+
528
+        // Menu Function
529
+        hideOptionMenu: hideOptionMenu,
530
+        showOptionMenu: showOptionMenu,
531
+        hideMenuItems: hideMenuItems,
532
+        showMenuItems: showMenuItems,
533
+        hideAllNonBaseMenuItem: hideAllNonBaseMenuItem,
534
+        showAllNonBaseMenuItem: showAllNonBaseMenuItem,
535
+        closeWindow: closeWindow,
536
+
537
+        // Share Function
538
+        initWxData: initWxData,
539
+        changeWxData: changeWxData,
540
+        fixedWxData: fixedWxData,
541
+
542
+        // Voice Function
543
+        voice: voice,
544
+        translateVoice: translateVoice,
545
+        startRecord: startRecord,
546
+        stopRecord: stopRecord,
547
+        playVoice: playVoice,
548
+        pauseVoice: pauseVoice,
549
+        stopVoice: stopVoice,
550
+        uploadVoice: uploadVoice,
551
+        downloadVoice: downloadVoice,
552
+
553
+        // Image Function
554
+        images: images,
555
+        chooseImage: chooseImage,
556
+        previewImage: previewImage,
557
+        uploadImage: uploadImage,
558
+        uploadImages: uploadImages,
559
+        downloadImage: downloadImage,
560
+        downloadImages: downloadImages,
561
+        getLocalImgData: getLocalImgData,
562
+
563
+        // Scan Function
564
+        scanQRCode: scanQRCode,
565
+        parseScanQRCodeResultStr: parseScanQRCodeResultStr,
566
+
567
+        // Pay Function
568
+        chooseWXPay: chooseWXPay,
569
+
570
+        // EnterpriseRedPacket Function
571
+        openEnterpriseRedPacket: openEnterpriseRedPacket
572
+    }
573
+    e.JSWE = e.V = v
574
+})(window)

+ 52 - 0
jdjos/urls.py

@@ -0,0 +1,52 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+"""jdjos URL Configuration
4
+
5
+The `urlpatterns` list routes URLs to views. For more information please see:
6
+    https://docs.djangoproject.com/en/1.11/topics/http/urls/
7
+Examples:
8
+Function views
9
+    1. Add an import:  from my_app import views
10
+    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
11
+Class-based views
12
+    1. Add an import:  from other_app.views import Home
13
+    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
14
+Including another URLconf
15
+    1. Import the include() function: from django.conf.urls import url, include
16
+    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
17
+"""
18
+from django.conf import settings
19
+from django.conf.urls import include, url
20
+from django.conf.urls.static import static
21
+from django.contrib import admin
22
+
23
+
24
+urlpatterns = [
25
+    url(r'^admin/', admin.site.urls),
26
+]
27
+
28
+urlpatterns += [
29
+    url(r'^api/', include('api.urls', namespace='api')),
30
+    url(r'^uniapi/', include('django_uniapi.urls', namespace='uniapi')),
31
+]
32
+
33
+urlpatterns += [
34
+    # url(r'^s/', include('django_short_url.urls', namespace='django_short_url')),
35
+]
36
+
37
+urlpatterns += [
38
+    url(r'^w/', include('django_we.urls', namespace='shortwechat')),
39
+    url(r'^we/', include('django_we.urls', namespace='wechat')),
40
+]
41
+
42
+urlpatterns += [
43
+    # url(r'^p/', include('page.urls', namespace='shortpage')),
44
+    # url(r'^page/', include('page.urls', namespace='page')),
45
+]
46
+
47
+urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
48
+urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
49
+
50
+# AdminSite
51
+admin.site.site_title = ''
52
+admin.site.site_header = 'My administration'

+ 17 - 0
jdjos/wsgi.py

@@ -0,0 +1,17 @@
1
+"""
2
+WSGI config for jdjos project.
3
+
4
+It exposes the WSGI callable as a module-level variable named ``application``.
5
+
6
+For more information on this file, see
7
+https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/
8
+"""
9
+
10
+import os
11
+
12
+from django.core.wsgi import get_wsgi_application
13
+
14
+
15
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "jdjos.settings")
16
+
17
+application = get_wsgi_application()

+ 23 - 0
manage.py

@@ -0,0 +1,23 @@
1
+#!/usr/bin/env python
2
+import os
3
+import sys
4
+
5
+
6
+if __name__ == "__main__":
7
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "jdjos.settings")
8
+    try:
9
+        from django.core.management import execute_from_command_line
10
+    except ImportError:
11
+        # The above import may fail for some other reason. Ensure that the
12
+        # issue is really that Django is missing to avoid masking other
13
+        # exceptions on Python 2.
14
+        try:
15
+            import django
16
+        except ImportError:
17
+            raise ImportError(
18
+                "Couldn't import Django. Are you sure it's installed and "
19
+                "available on your PYTHONPATH environment variable? Did you "
20
+                "forget to activate a virtual environment?"
21
+            )
22
+        raise
23
+    execute_from_command_line(sys.argv)

+ 10 - 0
pep8.sh

@@ -0,0 +1,10 @@
1
+#!/bin/bash
2
+
3
+# Ignoring autogenerated files
4
+#  -- Migration directories
5
+# Ignoring error codes
6
+#  -- E128 continuation line under-indented for visual indent
7
+#  -- E402 module level import not at top of file
8
+#  -- E501 line too long
9
+
10
+pycodestyle --exclude=build,migrations,.tox --ignore=E128,E402,E501 .

+ 7 - 0
requirements.txt

@@ -0,0 +1,7 @@
1
+StatusCode==1.0.0
2
+furl==2.0.0
3
+jsonfield==2.0.2
4
+mysqlclient==1.3.13
5
+-r requirements_dj.txt
6
+-r requirements_pywe.txt
7
+-r requirements_redis.txt

+ 3 - 0
requirements_deploy.txt

@@ -0,0 +1,3 @@
1
+ipdb==0.11
2
+ipython==5.6.0
3
+uwsgi==2.0.17

+ 2 - 0
requirements_dev.txt

@@ -0,0 +1,2 @@
1
+isort==4.3.9
2
+pycodestyle==2.4.0

+ 15 - 0
requirements_dj.txt

@@ -0,0 +1,15 @@
1
+Django==1.11.16
2
+django-admin==1.3.2
3
+django-detect==1.0.8
4
+django-file==1.0.3
5
+django-json-render==1.0.2
6
+django-json-response==1.1.5
7
+django-logit==1.1.3
8
+django-models-ext==1.1.8
9
+django-redis-connector==1.0.1
10
+django-response==1.1.1
11
+django-rlog==1.0.7
12
+django-short-url==1.1.3
13
+django-six==1.0.4
14
+django-uniapi==1.0.5
15
+django-we==1.4.2

+ 2 - 0
requirements_pywe.txt

@@ -0,0 +1,2 @@
1
+pywe-oauth==1.0.7
2
+pywe-pay==1.0.12

+ 3 - 0
requirements_redis.txt

@@ -0,0 +1,3 @@
1
+hiredis==1.0.0
2
+redis==2.10.6
3
+redis-extensions==1.2.5

+ 4 - 0
sysctl.sh

@@ -0,0 +1,4 @@
1
+#!/bin/bash
2
+
3
+sudo sysctl -w net.core.somaxconn=4096
4
+sudo sysctl -w net.core.netdev_max_backlog=50000

+ 0 - 0
utils/__init__.py


+ 0 - 0
utils/error/__init__.py


+ 77 - 0
utils/error/errno_utils.py

@@ -0,0 +1,77 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from StatusCode import BaseStatusCode, StatusCodeField
4
+
5
+
6
+class ParamStatusCode(BaseStatusCode):
7
+    """ 4000xx 参数相关错误码 """
8
+    PARAM_NOT_FOUND = StatusCodeField(400000, 'Param Not Found', description=u'参数不存在')
9
+
10
+
11
+class ProfileStatusCode(BaseStatusCode):
12
+    """ 4001xx 用户相关错误码 """
13
+    PROFILE_NOT_FOUND = StatusCodeField(400101, 'Profile Not Found', description=u'用户不存在')
14
+
15
+
16
+class PhoneStatusCode(BaseStatusCode):
17
+    """ 4002xx 手机相关错误码 """
18
+    INVALID_PHONE = StatusCodeField(400200, 'Invalid Phone', description=u'非法手机号')
19
+    PHONE_NOT_FOUND = StatusCodeField(400201, 'Phone Not Found', description=u'手机号不存在')
20
+    PHONE_ALREADY_EXISTS = StatusCodeField(400202, 'Phone Already Exists', description=u'手机号已存在')
21
+
22
+
23
+class OrderStatusCode(BaseStatusCode):
24
+    """ 4040xx 订单/支付相关错误码 """
25
+    UNIFIED_ORDER_FAIL = StatusCodeField(404000, 'Unified Order Fail', description=u'统一下单失败')
26
+    ORDER_NOT_FOUND = StatusCodeField(404001, 'Order Not Found', description=u'订单不存在')
27
+    # 订单支付状态
28
+    ORDER_NOT_PAY = StatusCodeField(404011, 'Order Not Pay', description=u'订单未支付')
29
+    ORDER_PAYING = StatusCodeField(404012, 'Order Paying', description=u'订单支付中')
30
+    ORDER_PAY_FAIL = StatusCodeField(404013, 'Order Pay Fail', description=u'微信支付失败')
31
+    # 通知校验状态
32
+    SIGN_CHECK_FAIL = StatusCodeField(404090, 'Sign Check Fail', description=u'签名校验失败')
33
+    FEE_CHECK_FAIL = StatusCodeField(404091, 'FEE Check Fail', description=u'金额校验失败')
34
+
35
+
36
+class PayStatusCode(BaseStatusCode):
37
+    """ 4041xx 支付相关错误码 """
38
+
39
+
40
+class WithdrawStatusCode(BaseStatusCode):
41
+    """ 4042xx 提现相关错误码 """
42
+    BALANCE_INSUFFICIENT = StatusCodeField(404200, 'Balance Insufficient', description=u'提现金额不足')
43
+
44
+
45
+class TokenStatusCode(BaseStatusCode):
46
+    """ 4090xx 票据相关错误码 """
47
+    TOKEN_NOT_FOUND = StatusCodeField(409001, 'Token Not Found', description=u'票据不存在')
48
+
49
+
50
+class SignatureStatusCode(BaseStatusCode):
51
+    """ 4091xx 签名校验错误 """
52
+    SIGNATURE_ERROR = StatusCodeField(409101, 'Signature Error', description=u'签名错误')
53
+
54
+
55
+class GVCodeStatusCode(BaseStatusCode):
56
+    """ 4092xx 图形验证码相关错误码 """
57
+    GRAPHIC_VCODE_ERROR = StatusCodeField(409201, 'Graphic VCode Error', description=u'图形验证码错误')
58
+
59
+
60
+class SVCodeStatusCode(BaseStatusCode):
61
+    """ 4093xx 短信验证码相关错误码 """
62
+    SMS_QUOTA_LIMIT = StatusCodeField(409300, 'SMS Quota Limit', description=u'短信次数超限')
63
+    SMS_VCODE_ERROR = StatusCodeField(409301, 'SMS VCode Error', description=u'验证码错误,请稍后重试')
64
+    SMS_VCODE_HAS_SEND = StatusCodeField(409302, 'SMS VCode Has Send', description=u'验证码已发送,请勿重复获取')
65
+
66
+
67
+class InsufficientStatusCode(BaseStatusCode):
68
+    """ 4095xx 不足相关错误码 """
69
+    BALANCE_INSUFFICIENT = StatusCodeField(409501, 'Balance Insufficient', description=u'余额不足')
70
+    INTEGRAL_INSUFFICIENT = StatusCodeField(409502, 'Integral Insufficient', description=u'积分不足')
71
+
72
+
73
+class PermissionStatusCode(BaseStatusCode):
74
+    """ 4099xx 权限相关错误码 """
75
+    PERMISSION_DENIED = StatusCodeField(409900, 'Permission Denied', description=u'权限不足')
76
+    UPLOAD_PERMISSION_DENIED = StatusCodeField(409910, 'Upload Permission Denied', description=u'上传权限不足')
77
+    UPDATE_PERMISSION_DENIED = StatusCodeField(409930, 'Update Permission Denied', description=u'更新权限不足')

+ 24 - 0
utils/error/response_utils.py

@@ -0,0 +1,24 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from json_response import JsonpResponse, JsonResponse
4
+from StatusCode import StatusCodeField
5
+
6
+
7
+def response_data(status_code=200, message=None, description=None, data={}, **kwargs):
8
+    return dict({
9
+        'status': status_code,
10
+        'message': message,
11
+        'description': description,
12
+        'data': data,
13
+    }, **kwargs)
14
+
15
+
16
+def response(status_code=200, message=None, description=None, data={}, msg_args=[], msg_kwargs={}, desc_args=[], desc_kwargs={}, request=None, callback=None, **kwargs):
17
+    # Final Message and Description
18
+    message, description = (message or status_code.message, description or status_code.description) if isinstance(status_code, StatusCodeField) else (message, description)
19
+    # Final Response Data
20
+    resp_data = response_data(status_code, (message or '').format(*msg_args, **msg_kwargs), (description or '').format(*desc_args, **desc_kwargs), data, **kwargs)
21
+    # Assign Callback
22
+    callback = callback or (request and request.GET.get('callback'))
23
+    # Call JsonResponse or JsonpResponse
24
+    return JsonpResponse(callback, resp_data, safe=False) if callback else JsonResponse(resp_data, safe=False)

+ 0 - 0
utils/redis/__init__.py


+ 6 - 0
utils/redis/connect.py

@@ -0,0 +1,6 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.conf import settings
4
+
5
+
6
+r = settings.REDIS_CACHE

+ 1 - 0
utils/redis/rkeys.py

@@ -0,0 +1 @@
1
+# -*- coding: utf-8 -*-

+ 0 - 0
utils/user/__init__.py


+ 18 - 0
utils/user/userinfo_save.py

@@ -0,0 +1,18 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+
4
+def userinfo_save(userinfo):
5
+    """ Save profile or something else """
6
+    # from account.models import UserInfo
7
+    # from django.conf import settings
8
+    #
9
+    # unique_identifier = userinfo.get(settings.WECHAT_UNIQUE_IDENTIFICATION, '')
10
+    #
11
+    # user, created = UserInfo.objects.select_for_update().get_or_create(**{settings.WECHAT_UNIQUE_IDENTIFICATION: unique_identifier})
12
+    # user.unionid = userinfo.get('unionid', '')
13
+    # user.openid = userinfo.get('openid', '')
14
+    # user.nickname = userinfo.get('nickname', '')
15
+    # user.avatar = userinfo.get('headimgurl', '')
16
+    # user.save()
17
+    #
18
+    # return user

Kodo/kodo - Gogs: Go Git Service

3 Commissions (ce35cc64ef6a03db3183615af8a2f06aade9ce8a)

Auteur SHA1 Message Date
  Brightcells 6626af8a8d add api lensman_wx_authorize_api 9 ans auparavant
  Brightcells fabef63211 set line_length=200 for isort 9 ans auparavant
  Brightcells f72ccb1875 isort import 9 ans auparavant