170
+
171
+    function initWxData(data, flag) {
172
+        for(var d in data) {if (d in wxData) wxData[d] = data[d]}
173
+        if (flag) fixedWxData()
174
+    }
175
+
176
+    function changeWxData(key, value, flag) {
177
+        if (key in falDwxDataata) {wxData[key] = value}
178
+        if (flag) fixedWxData()
179
+    }
180
+
181
+    function fixedWxData() {
182
+        if ('undefined' !== typeof wxApiFun) wxApiFun()
183
+    }
184
+
185
+    // 5 图片接口
186
+    // 5.1 拍照、本地选图
187
+    var images = {
188
+        localIds: [],
189
+        serverIds: []
190
+    };
191
+    // function chooseImage(count, directUpload, isShowProgressTips) {
192
+    function chooseImage(choose_params) {
193
+        if ('undefined' === typeof choose_params) choose_params = {}
194
+        wx.chooseImage({
195
+            count: choose_params.count || 9, // 默认9
196
+            sizeType: choose_params.sizeType || ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
197
+            sourceType: choose_params.sourceType || ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
198
+            success: function (res) {
199
+                images.localIds = res.localIds; // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片
200
+                // 判断是否直接上传
201
+                if (choose_params.directUpload) {setTimeout(uploadImages({localIds: images.localIds, isShowProgressTips: choose_params.isShowProgressTips || 1}), 100)}
202
+                // 拍照、本地选图成功后的回调函数
203
+                if (JSWE.wxChooseImageSuccess) {JSWE.wxChooseImageSuccess(res)}
204
+            }
205
+        });
206
+    }
207
+
208
+    // 5.2 图片预览
209
+    function previewImage(preview_params) {
210
+        wx.previewImage({
211
+            current: preview_params.current, // 当前显示图片的链接,不填则默认为 urls 的第一张
212
+            urls: preview_params.urls // 需要预览的图片链接列表
213
+        });
214
+    }
215
+
216
+    // 5.3 上传图片
217
+    // function uploadImage(localId, isShowProgressTips) {
218
+    function uploadImage(upload_params) {
219
+        // 上传图片为异步处理,重复上传同一图片,返回的serverId也是不同的
220
+        wx.uploadImage({
221
+            localId: upload_params.localId, // 需要上传的图片的本地ID,由chooseImage接口获得
222
+            isShowProgressTips: upload_params.isShowProgressTips || 1, // 默认为1,显示进度提示
223
+            success: function (res) {
224
+                images.serverIds.push(res.serverId); // 返回图片的服务器端ID
225
+                // 上传图片成功后的回调函数
226
+                if (JSWE.wxUploadImageSuccess) {JSWE.wxUploadImageSuccess(res)}
227
+            }
228
+        });
229
+    }
230
+
231
+    // function uploadImages(localIds, isShowProgressTips) {
232
+    function uploadImages(upload_params) {
233
+        var localIds = upload_params.localIds, isShowProgressTips = upload_params.isShowProgressTips || 1
234
+        images.serverIds = [];
235
+        for (var idx in localIds) {uploadImage({localId: localIds[idx], isShowProgressTips: isShowProgressTips})}
236
+    }
237
+
238
+    // 9 微信原生接口
239
+    // 9.1.1 扫描二维码并返回结果
240
+    // 9.1.2 扫描二维码并返回结果
241
+    function scanQRCode(scan_params) {
242
+        if ('undefined' === typeof scan_params) scan_params = {}
243
+        wx.scanQRCode({
244
+            needResult: scan_params.needResult || 0,  // 默认为0,0扫描结果由微信处理,1直接返回扫描结果
245
+            scanType: scan_params.scanType || ['qrCode', 'barCode'],  // 可以指定扫二维码还是一维码,默认二者都有
246
+            success: function (res) {  // 当 needResult 为 1 时,扫码返回的结果
247
+                if (JSWE.wxScanQRCodeSuccess) {JSWE.wxScanQRCodeSuccess(res)}
248
+            }
249
+        });
250
+    }
251
+
252
+    // QRCode & BarCode is different
253
+    function parseScanQRCodeResultStr(resultStr) {
254
+        var strs = resultStr.split(',')
255
+        return strs[strs.length - 1]
256
+    }
257
+
258
+    // 10 微信支付接口
259
+    // 10.1 发起一个支付请求
260
+    function chooseWXPay(wxpay_params) {
261
+        wx.chooseWXPay({
262
+            timestamp: wxpay_params.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
263
+            nonceStr: wxpay_params.nonceStr, // 支付签名随机串,不长于 32 位
264
+            package: wxpay_params.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
265
+            signType: wxpay_params.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
266
+            paySign: wxpay_params.paySign, // 支付签名
267
+            success: function (res) {
268
+                // 支付成功后的回调函数
269
+                if (JSWE.wxPaySuccess) {JSWE.wxPaySuccess(res)}
270
+            }
271
+        })
272
+    }
273
+
274
+    // xx 微信原生企业红包接口
275
+    // xx.1 发起一个发送原生企业红包请求
276
+    function openEnterpriseRedPacket(wxredpack_params) {
277
+        wx.openEnterpriseRedPacket({
278
+            timeStamp: wxredpack_params.timeStamp, // 红包签名时间戳,注意原生企业红包接口timeStamp字段名需大写其中的S字符,而支付接口timeStamp字段名无需大写其中的S字符。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
279
+            nonceStr: wxredpack_params.nonceStr, // 红包签名随机串,不长于 32 位
280
+            package: encodeURIComponent(wxredpack_params.package), // 发放红包接口返回的prepay_id参数值,提交格式如:prepay_id=***)
281
+            signType: wxredpack_params.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
282
+            paySign: wxredpack_params.paySign, // 红包签名
283
+            success: function (res) {
284
+                // 发送原生企业红包成功后的回调函数
285
+                if (JSWE.wxEnterpriseRedPacketSuccess) {JSWE.wxEnterpriseRedPacketSuccess(res)}
286
+            }
287
+        })
288
+    }
289
+
290
+    var v = {
291
+        version: '1.0.5',
292
+
293
+        // Basic Vars
294
+        config: config,
295
+        wxData: wxData,
296
+        jsApiList: jsApiList,
297
+
298
+        // Weixin Function
299
+        isOpenInWeixin: isOpenInWeixin,
300
+        getWeixinVersion: getWeixinVersion,
301
+        isWeixinVersion: isWeixinVersion,
302
+
303
+        // Menu Function
304
+        hideOptionMenu: hideOptionMenu,
305
+        showOptionMenu: showOptionMenu,
306
+        closeWindow: closeWindow,
307
+
308
+        // Share Function
309
+        initWxData: initWxData,
310
+        changeWxData: changeWxData,
311
+        fixedWxData: fixedWxData,
312
+
313
+        // Image Function
314
+        images: images,
315
+        chooseImage: chooseImage,
316
+        previewImage: previewImage,
317
+        uploadImage: uploadImage,
318
+        uploadImages: uploadImages,
319
+
320
+        // Scan Function
321
+        scanQRCode: scanQRCode,
322
+        parseScanQRCodeResultStr: parseScanQRCodeResultStr,
323
+
324
+        // Pay Function
325
+        chooseWXPay: chooseWXPay,
326
+
327
+        // EnterpriseRedPacket Function
328
+        openEnterpriseRedPacket: openEnterpriseRedPacket
329
+    }
330
+    e.JSWE = e.V = v
331
+})(window)

+ 32 - 0
manual/urls.py

@@ -0,0 +1,32 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+"""manual 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
+    url(r'^api/', include('api.urls', namespace='api')),
27
+    url(r'^uniapi/', include('django_uniapi.urls', namespace='uniapi')),
28
+    url(r'^we/', include('django_we.urls', namespace='wechat')),
29
+]
30
+
31
+urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
32
+urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

+ 17 - 0
manual/wsgi.py

@@ -0,0 +1,17 @@
1
+"""
2
+WSGI config for manual 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", "manual.settings")
16
+
17
+application = get_wsgi_application()

BIN
media/file/201708/1502869267.33.png


BIN
media/file/201708/1502869283.66.png


BIN
media/file/201708/1502870309.11.png


BIN
media/file/201708/1502870443.78.png


+ 0 - 0
message/__init__.py


+ 13 - 0
message/admin.py

@@ -0,0 +1,13 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.contrib import admin
4
+
5
+from message.models import MessageInfo
6
+
7
+
8
+class MessageInfoAdmin(admin.ModelAdmin):
9
+    list_display = ('msg_image', 'msg_image_airtime', 'msg_image_deadline', 'status', 'created_at', 'updated_at')
10
+    list_filter = ('status', )
11
+
12
+
13
+admin.site.register(MessageInfo, MessageInfoAdmin)

+ 8 - 0
message/apps.py

@@ -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 MessageConfig(AppConfig):
8
+    name = 'message'

+ 33 - 0
message/migrations/0001_initial.py

@@ -0,0 +1,33 @@
1
+# -*- coding: utf-8 -*-
2
+# Generated by Django 1.11.3 on 2017-08-16 07:03
3
+from __future__ import unicode_literals
4
+
5
+from django.db import migrations, models
6
+import message.models
7
+
8
+
9
+class Migration(migrations.Migration):
10
+
11
+    initial = True
12
+
13
+    dependencies = [
14
+    ]
15
+
16
+    operations = [
17
+        migrations.CreateModel(
18
+            name='MessageInfo',
19
+            fields=[
20
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21
+                ('status', models.BooleanField(db_index=True, default=True, help_text='\u72b6\u6001', verbose_name='status')),
22
+                ('created_at', models.DateTimeField(auto_now_add=True, help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at')),
23
+                ('updated_at', models.DateTimeField(auto_now=True, help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at')),
24
+                ('msg_image', models.ImageField(blank=True, help_text='\u6d88\u606f\u56fe\u7247', null=True, upload_to=message.models.upload_path, verbose_name='msg_image')),
25
+                ('msg_image_airtime', models.DateTimeField(blank=True, help_text='\u6d88\u606f\u56fe\u7247\u5f00\u59cb\u65e5\u671f', null=True, verbose_name='msg_image_airtime')),
26
+                ('msg_image_deadline', models.DateTimeField(blank=True, help_text='\u6d88\u606f\u56fe\u7247\u622a\u6b62\u65e5\u671f', null=True, verbose_name='msg_image_deadline')),
27
+            ],
28
+            options={
29
+                'verbose_name': 'messageinfo',
30
+                'verbose_name_plural': 'messageinfo',
31
+            },
32
+        ),
33
+    ]

+ 19 - 0
message/migrations/0002_auto_20170816_1604.py

@@ -0,0 +1,19 @@
1
+# -*- coding: utf-8 -*-
2
+# Generated by Django 1.11.3 on 2017-08-16 08:04
3
+from __future__ import unicode_literals
4
+
5
+from django.db import migrations
6
+
7
+
8
+class Migration(migrations.Migration):
9
+
10
+    dependencies = [
11
+        ('message', '0001_initial'),
12
+    ]
13
+
14
+    operations = [
15
+        migrations.AlterModelOptions(
16
+            name='messageinfo',
17
+            options={'verbose_name': '\u56fe\u7247\u6d88\u606f', 'verbose_name_plural': '\u56fe\u7247\u6d88\u606f'},
18
+        ),
19
+    ]

+ 0 - 0
message/migrations/__init__.py


+ 41 - 0
message/models.py

@@ -0,0 +1,41 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+import os
4
+
5
+from django.db import models
6
+from django.utils.translation import ugettext_lazy as _
7
+from TimeConvert import TimeConvert as tc
8
+
9
+from manual.basemodels import CreateUpdateMixin
10
+from utils.url_utils import upload_file_url
11
+
12
+
13
+def upload_path(instance, old_filename):
14
+    return 'file/{ym}/{stamp}{ext}'.format(
15
+        ym=tc.local_string(format='%Y%m'),
16
+        stamp=tc.local_timestamp(ms=True),
17
+        ext=os.path.splitext(old_filename)[1].lower(),
18
+    )
19
+
20
+
21
+class MessageInfo(CreateUpdateMixin):
22
+    msg_image = models.ImageField(_(u'msg_image'), upload_to=upload_path, blank=True, null=True, help_text=u'消息图片')
23
+    msg_image_airtime = models.DateTimeField(_(u'msg_image_airtime'), blank=True, null=True, help_text=u'消息图片开始日期')
24
+    msg_image_deadline = models.DateTimeField(_(u'msg_image_deadline'), blank=True, null=True, help_text=u'消息图片截止日期')
25
+
26
+    class Meta:
27
+        verbose_name = _(u'图片消息')
28
+        verbose_name_plural = _(u'图片消息')
29
+
30
+    def __unicode__(self):
31
+        return unicode(self.pk)
32
+
33
+    @property
34
+    def msg_image_url(self):
35
+        return upload_file_url(self.msg_image)
36
+
37
+    @property
38
+    def data(self):
39
+        return {
40
+            'msg_image_url': self.msg_image_url,
41
+        }

+ 19 - 0
message/msg_views.py

@@ -0,0 +1,19 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from logit import logit
5
+from TimeConvert import TimeConvert as tc
6
+
7
+from message.models import MessageInfo
8
+from utils.error.response_utils import response
9
+
10
+
11
+@logit
12
+def msg_list_api(request):
13
+    curdt = tc.utc_datetime()
14
+    msgs = MessageInfo.objects.filter(msg_image_airtime__lte=curdt, msg_image_deadline__gt=curdt, status=True)
15
+    msgs = [msg.data for msg in msgs]
16
+
17
+    return response(200, 'Get Message List Success', u'获取消息列表成功', {
18
+        'msgs': msgs,
19
+    })

+ 7 - 0
message/tests.py

@@ -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.

+ 7 - 0
message/views.py

@@ -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.

+ 9 - 0
pep8.sh

@@ -0,0 +1,9 @@
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
+#  -- E501 line too long
8
+
9
+pep8 --exclude=migrations --ignore=E128,E501 .

+ 15 - 0
requirements.txt

@@ -0,0 +1,15 @@
1
+-e git+https://github.com/andymccurdy/redis-py.git#egg=redis-py
2
+Django==1.11.3
3
+MySQL-python==1.2.5
4
+StatusCode==1.0.0
5
+TimeConvert==1.4.1
6
+django-admin==1.0.4
7
+django-detect==1.0.5
8
+django-json-response==1.1.5
9
+django-logit==1.0.6
10
+django-paginator2==1.0.3
11
+django-shortuuidfield==0.1.3
12
+django-uniapi==1.0.0
13
+django-we==1.0.7
14
+hiredis==0.2.0
15
+redis-extensions==1.1.1

+ 0 - 0
support/__init__.py


+ 25 - 0
support/admin.py

@@ -0,0 +1,25 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.contrib import admin
4
+
5
+from support.models import MachineBackInfo, MachineBodyInfo, MachineSupportPrebookInfo
6
+
7
+
8
+class MachineBodyInfoAdmin(admin.ModelAdmin):
9
+    list_display = ('body', 'status', 'created_at', 'updated_at')
10
+    list_filter = ('status', )
11
+
12
+
13
+class MachineBackInfoAdmin(admin.ModelAdmin):
14
+    list_display = ('back', 'status', 'created_at', 'updated_at')
15
+    list_filter = ('status', )
16
+
17
+
18
+class MachineSupportPrebookInfoAdmin(admin.ModelAdmin):
19
+    list_display = ('user_id', 'name', 'sex', 'phone', 'weekday', 'timeslice', 'body', 'back', 'handle_status', 'status', 'created_at', 'updated_at')
20
+    list_filter = ('weekday', 'timeslice', 'body', 'back', 'handle_status', 'status')
21
+
22
+
23
+admin.site.register(MachineBodyInfo, MachineBodyInfoAdmin)
24
+admin.site.register(MachineBackInfo, MachineBackInfoAdmin)
25
+admin.site.register(MachineSupportPrebookInfo, MachineSupportPrebookInfoAdmin)

+ 8 - 0
support/apps.py

@@ -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 SupportConfig(AppConfig):
8
+    name = 'support'

+ 66 - 0
support/migrations/0001_initial.py

@@ -0,0 +1,66 @@
1
+# -*- coding: utf-8 -*-
2
+# Generated by Django 1.11.3 on 2017-08-16 07:03
3
+from __future__ import unicode_literals
4
+
5
+from django.db import migrations, models
6
+import django.db.models.deletion
7
+
8
+
9
+class Migration(migrations.Migration):
10
+
11
+    initial = True
12
+
13
+    dependencies = [
14
+    ]
15
+
16
+    operations = [
17
+        migrations.CreateModel(
18
+            name='MachineBackInfo',
19
+            fields=[
20
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21
+                ('status', models.BooleanField(db_index=True, default=True, help_text='\u72b6\u6001', verbose_name='status')),
22
+                ('created_at', models.DateTimeField(auto_now_add=True, help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at')),
23
+                ('updated_at', models.DateTimeField(auto_now=True, help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at')),
24
+                ('back', models.CharField(blank=True, help_text='\u673a\u80cc', max_length=255, null=True, unique=True, verbose_name='back')),
25
+            ],
26
+            options={
27
+                'verbose_name': '\u673a\u80cc\u914d\u7f6e',
28
+                'verbose_name_plural': '\u673a\u80cc\u914d\u7f6e',
29
+            },
30
+        ),
31
+        migrations.CreateModel(
32
+            name='MachineBodyInfo',
33
+            fields=[
34
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
35
+                ('status', models.BooleanField(db_index=True, default=True, help_text='\u72b6\u6001', verbose_name='status')),
36
+                ('created_at', models.DateTimeField(auto_now_add=True, help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at')),
37
+                ('updated_at', models.DateTimeField(auto_now=True, help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at')),
38
+                ('body', models.CharField(blank=True, help_text='\u673a\u8eab', max_length=255, null=True, unique=True, verbose_name='body')),
39
+            ],
40
+            options={
41
+                'verbose_name': '\u673a\u8eab\u914d\u7f6e',
42
+                'verbose_name_plural': '\u673a\u8eab\u914d\u7f6e',
43
+            },
44
+        ),
45
+        migrations.CreateModel(
46
+            name='MachineSupportPrebookInfo',
47
+            fields=[
48
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
49
+                ('status', models.BooleanField(db_index=True, default=True, help_text='\u72b6\u6001', verbose_name='status')),
50
+                ('created_at', models.DateTimeField(auto_now_add=True, help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at')),
51
+                ('updated_at', models.DateTimeField(auto_now=True, help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at')),
52
+                ('user_id', models.CharField(blank=True, db_index=True, help_text='\u7528\u6237\u552f\u4e00\u6807\u8bc6', max_length=255, null=True, verbose_name='user_id')),
53
+                ('name', models.CharField(blank=True, help_text='\u7528\u6237\u59d3\u540d', max_length=255, null=True, verbose_name='name')),
54
+                ('sex', models.IntegerField(choices=[(1, '\u7537'), (0, '\u5973')], default=1, help_text='\u7528\u6237\u6027\u522b', verbose_name='sex')),
55
+                ('phone', models.CharField(blank=True, db_index=True, help_text='\u7528\u6237\u7535\u8bdd', max_length=255, null=True, verbose_name='phone')),
56
+                ('weekday', models.IntegerField(db_index=True, default=0, help_text='\u5468\u51e0\uff1a\u5468\u65e5\u4e3a0', verbose_name='weekday')),
57
+                ('timeslice', models.IntegerField(choices=[(0, '09:00 - 12:00'), (0, '12:00 - 14:00'), (0, '14:00 - 18:00'), (0, '18:00 - 21:00')], db_index=True, default=0, help_text='\u65f6\u95f4\u6bb5', verbose_name='timeslice')),
58
+                ('back', models.ForeignKey(blank=True, help_text='\u673a\u80cc', null=True, on_delete=django.db.models.deletion.CASCADE, to='support.MachineBackInfo', verbose_name='back')),
59
+                ('body', models.ForeignKey(blank=True, help_text='\u673a\u8eab', null=True, on_delete=django.db.models.deletion.CASCADE, to='support.MachineBodyInfo', verbose_name='body')),
60
+            ],
61
+            options={
62
+                'verbose_name': 'machinesupportprebookinfo',
63
+                'verbose_name_plural': 'machinesupportprebookinfo',
64
+            },
65
+        ),
66
+    ]

+ 25 - 0
support/migrations/0002_auto_20170816_1509.py

@@ -0,0 +1,25 @@
1
+# -*- coding: utf-8 -*-
2
+# Generated by Django 1.11.3 on 2017-08-16 07:09
3
+from __future__ import unicode_literals
4
+
5
+from django.db import migrations, models
6
+
7
+
8
+class Migration(migrations.Migration):
9
+
10
+    dependencies = [
11
+        ('support', '0001_initial'),
12
+    ]
13
+
14
+    operations = [
15
+        migrations.AddField(
16
+            model_name='machinebackinfo',
17
+            name='position',
18
+            field=models.IntegerField(default=1, help_text='\u6392\u5e8f', verbose_name='position'),
19
+        ),
20
+        migrations.AddField(
21
+            model_name='machinebodyinfo',
22
+            name='position',
23
+            field=models.IntegerField(default=1, help_text='\u6392\u5e8f', verbose_name='position'),
24
+        ),
25
+    ]

+ 20 - 0
support/migrations/0003_machinesupportprebookinfo_handle_status.py

@@ -0,0 +1,20 @@
1
+# -*- coding: utf-8 -*-
2
+# Generated by Django 1.11.3 on 2017-08-16 07:34
3
+from __future__ import unicode_literals
4
+
5
+from django.db import migrations, models
6
+
7
+
8
+class Migration(migrations.Migration):
9
+
10
+    dependencies = [
11
+        ('support', '0002_auto_20170816_1509'),
12
+    ]
13
+
14
+    operations = [
15
+        migrations.AddField(
16
+            model_name='machinesupportprebookinfo',
17
+            name='handle_status',
18
+            field=models.IntegerField(choices=[(0, '\u672a\u5904\u7406'), (1, '\u5df2\u8054\u7cfb'), (10, '\u5df2\u5904\u7406')], default=0, help_text='\u5904\u7406\u72b6\u6001', verbose_name='handle_status'),
19
+        ),
20
+    ]

+ 20 - 0
support/migrations/0004_auto_20170816_1604.py

@@ -0,0 +1,20 @@
1
+# -*- coding: utf-8 -*-
2
+# Generated by Django 1.11.3 on 2017-08-16 08:04
3
+from __future__ import unicode_literals
4
+
5
+from django.db import migrations, models
6
+
7
+
8
+class Migration(migrations.Migration):
9
+
10
+    dependencies = [
11
+        ('support', '0003_machinesupportprebookinfo_handle_status'),
12
+    ]
13
+
14
+    operations = [
15
+        migrations.AlterField(
16
+            model_name='machinesupportprebookinfo',
17
+            name='timeslice',
18
+            field=models.IntegerField(choices=[(0, '09:00 - 12:00'), (1, '12:00 - 14:00'), (2, '14:00 - 18:00'), (3, '18:00 - 21:00')], db_index=True, default=0, help_text='\u65f6\u95f4\u6bb5', verbose_name='timeslice'),
19
+        ),
20
+    ]

+ 0 - 0
support/migrations/__init__.py


+ 94 - 0
support/models.py

@@ -0,0 +1,94 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.db import models
4
+from django.utils.translation import ugettext_lazy as _
5
+
6
+from manual.basemodels import CreateUpdateMixin
7
+
8
+
9
+class MachineBodyInfo(CreateUpdateMixin):
10
+    body = models.CharField(_(u'body'), max_length=255, blank=True, null=True, help_text=u'机身', unique=True)
11
+    position = models.IntegerField(_(u'position'), default=1, help_text=u'排序')
12
+
13
+    class Meta:
14
+        verbose_name = _(u'机身配置')
15
+        verbose_name_plural = _(u'机身配置')
16
+
17
+    def __unicode__(self):
18
+        return unicode(self.body)
19
+
20
+    @property
21
+    def data(self):
22
+        return {
23
+            'pk': self.pk,
24
+            'body': self.body,
25
+        }
26
+
27
+
28
+class MachineBackInfo(CreateUpdateMixin):
29
+    back = models.CharField(_(u'back'), max_length=255, blank=True, null=True, help_text=u'机背', unique=True)
30
+    position = models.IntegerField(_(u'position'), default=1, help_text=u'排序')
31
+
32
+    class Meta:
33
+        verbose_name = _(u'机背配置')
34
+        verbose_name_plural = _(u'机背配置')
35
+
36
+    def __unicode__(self):
37
+        return unicode(self.back)
38
+
39
+    @property
40
+    def data(self):
41
+        return {
42
+            'pk': self.pk,
43
+            'back': self.back,
44
+        }
45
+
46
+
47
+class MachineSupportPrebookInfo(CreateUpdateMixin):
48
+    MALE = 1
49
+    FEMALE = 0
50
+
51
+    SEX_TYPE = (
52
+        (MALE, u'男'),
53
+        (FEMALE, u'女'),
54
+    )
55
+
56
+    SLICE0 = 0
57
+    SLICE1 = 1
58
+    SLICE2 = 2
59
+    SLICE3 = 3
60
+
61
+    TIME_SLICE = (
62
+        (SLICE0, u'09:00 - 12:00'),
63
+        (SLICE1, u'12:00 - 14:00'),
64
+        (SLICE2, u'14:00 - 18:00'),
65
+        (SLICE3, u'18:00 - 21:00'),
66
+    )
67
+
68
+    NOT_HANDLE = 0
69
+    HAS_CONTACTED = 1
70
+    HAS_HANDLED = 10
71
+
72
+    HANDLE_STATUS = (
73
+        (NOT_HANDLE, u'未处理'),
74
+        (HAS_CONTACTED, u'已联系'),
75
+        (HAS_HANDLED, u'已处理'),
76
+    )
77
+
78
+    user_id = models.CharField(_(u'user_id'), max_length=255, blank=True, null=True, help_text=u'用户唯一标识', db_index=True)
79
+    name = models.CharField(_(u'name'), max_length=255, blank=True, null=True, help_text=u'用户姓名')
80
+    sex = models.IntegerField(_(u'sex'), choices=SEX_TYPE, default=MALE, help_text=u'用户性别')
81
+    phone = models.CharField(_(u'phone'), max_length=255, blank=True, null=True, help_text=u'用户电话', db_index=True)
82
+    weekday = models.IntegerField(_(u'weekday'), default=0, help_text=u'周几:周日为0', db_index=True)
83
+    timeslice = models.IntegerField(_(u'timeslice'), default=SLICE0, choices=TIME_SLICE, help_text=u'时间段', db_index=True)
84
+    body = models.ForeignKey(MachineBodyInfo, verbose_name=_(u'body'), blank=True, null=True, help_text=u'机身')
85
+    back = models.ForeignKey(MachineBackInfo, verbose_name=_(u'back'), blank=True, null=True, help_text=u'机背')
86
+
87
+    handle_status = models.IntegerField(_(u'handle_status'), choices=HANDLE_STATUS, default=NOT_HANDLE, help_text=u'处理状态')
88
+
89
+    class Meta:
90
+        verbose_name = _(u'machinesupportprebookinfo')
91
+        verbose_name_plural = _(u'machinesupportprebookinfo')
92
+
93
+    def __unicode__(self):
94
+        return unicode(self.pk)

+ 7 - 0
support/tests.py

@@ -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.

+ 57 - 0
support/views.py

@@ -0,0 +1,57 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from logit import logit
5
+
6
+from support.models import MachineBackInfo, MachineBodyInfo, MachineSupportPrebookInfo
7
+from utils.error.errno_utils import MachineStatusCode
8
+from utils.error.response_utils import response
9
+
10
+
11
+@logit
12
+def support_info_api(request):
13
+    bodys = MachineBodyInfo.objects.filter(status=True).order_by('position')
14
+    bodys = [body.data for body in bodys]
15
+
16
+    backs = MachineBackInfo.objects.filter(status=True).order_by('position')
17
+    backs = [back.data for back in backs]
18
+
19
+    return response(200, 'Get Support Info Success', u'获取支持信息成功', {
20
+        'bodys': bodys,
21
+        'backs': backs,
22
+    })
23
+
24
+
25
+@logit
26
+def support_prebook_submit_api(request):
27
+    user_id = request.POST.get('user_id', '')
28
+    name = request.POST.get('name', '')
29
+    sex = int(request.POST.get('sex', 0))
30
+    phone = request.POST.get('phone', '')
31
+    weekday = int(request.POST.get('weekday', 0))
32
+    timeslice = int(request.POST.get('timeslice', 0))
33
+    body = int(request.POST.get('body', 0))
34
+    back = int(request.POST.get('back', 0))
35
+
36
+    try:
37
+        body = MachineBodyInfo.objects.get(pk=body)
38
+    except MachineBodyInfo.DoesNotExist:
39
+        return response(MachineStatusCode.MACHINE_BODY_NOT_FOUND)
40
+
41
+    try:
42
+        back = MachineBackInfo.objects.get(pk=back)
43
+    except MachineBackInfo.DoesNotExist:
44
+        return response(MachineStatusCode.MACHINE_BACK_NOT_FOUND)
45
+
46
+    MachineSupportPrebookInfo.objects.create(
47
+        user_id=user_id,
48
+        name=name,
49
+        sex=sex,
50
+        phone=phone,
51
+        weekday=weekday,
52
+        timeslice=timeslice,
53
+        body=body,
54
+        back=back,
55
+    )
56
+
57
+    return response(200, 'Submit Support Info Success', u'提交支持信息成功')

+ 0 - 0
utils/__init__.py


+ 0 - 0
utils/error/__init__.py


+ 43 - 0
utils/error/errno_utils.py

@@ -0,0 +1,43 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from StatusCode import BaseStatusCode, StatusCodeField
4
+
5
+
6
+class ProfileStatusCode(BaseStatusCode):
7
+    """ 用户相关错误码 4001xx """
8
+    PROFILE_NOT_FOUND = StatusCodeField(400101, 'Profile Not Found', description=u'用户不存在')
9
+    # 手机号
10
+    PHONE_ALREADY_EXISTS = StatusCodeField(400105, 'Phone Already Exists', description=u'手机号已经存在')
11
+
12
+
13
+class MachineStatusCode(BaseStatusCode):
14
+    """ 机器相关错误码 4021xx """
15
+    MACHINE_BODY_NOT_FOUND = StatusCodeField(402101, 'Machine Body Not Found', description=u'机身不存在')
16
+    MACHINE_BACK_NOT_FOUND = StatusCodeField(402102, 'Machine Back Not Found', description=u'机背不存在')
17
+
18
+
19
+class OrderStatusCode(BaseStatusCode):
20
+    """ 订单/支付相关错误码 4040xx """
21
+    UNIFIED_ORDER_FAIL = StatusCodeField(404000, 'Unified Order Fail', description=u'统一下单失败')
22
+    ORDER_NOT_FOUND = StatusCodeField(404001, 'Order Not Found', description=u'订单不存在')
23
+    # 订单支付状态
24
+    ORDER_NOT_PAY = StatusCodeField(404011, 'Order Not Pay', description=u'订单未支付')
25
+    ORDER_PAYING = StatusCodeField(404012, 'Order Paying', description=u'订单支付中')
26
+    ORDER_PAY_FAIL = StatusCodeField(404013, 'Order Pay Fail', description=u'微信支付失败')
27
+    # 通知校验状态
28
+    SIGN_CHECK_FAIL = StatusCodeField(404090, 'Sign Check Fail', description=u'签名校验失败')
29
+    FEE_CHECK_FAIL = StatusCodeField(404091, 'FEE Check Fail', description=u'金额校验失败')
30
+
31
+
32
+class PayStatusCode(BaseStatusCode):
33
+    """ 支付相关错误码 4041xx """
34
+
35
+
36
+class WithdrawStatusCode(BaseStatusCode):
37
+    """ 提现相关错误码 4042xx """
38
+    BALANCE_INSUFFICIENT = StatusCodeField(404200, 'Balance Insufficient', description=u'提现金额不足')
39
+
40
+
41
+class TokenStatusCode(BaseStatusCode):
42
+    """ 票据相关错误码 4090xx """
43
+    TOKEN_NOT_FOUND = StatusCodeField(409901, 'Token Not Found', description=u'票据不存在')

+ 18 - 0
utils/error/response_utils.py

@@ -0,0 +1,18 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.http import 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={}, **kwargs):
17
+    message, description = (message or status_code.message, description or status_code.description) if isinstance(status_code, StatusCodeField) else (message, description)
18
+    return JsonResponse(response_data(status_code, message, description, data, **kwargs), 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 -*-

+ 7 - 0
utils/url_utils.py

@@ -0,0 +1,7 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.conf import settings
4
+
5
+
6
+def upload_file_url(file_path):
7
+    return file_path and ('{}{}'.format(settings.DOMAIN, file_path.url)) or ''

kodo - Gogs: Go Git Service

Brak opisu

views.py 7.7KB

    # -*- coding: utf-8 -*- from django.conf import settings from django.db import transaction from django_curtail_uuid import CurtailUUID from django_logit import logit from django_response import response from ipaddr import client_ip from pywe_membercard import get_miniapp_extraData from pywe_miniapp import get_session_info, get_session_key, get_userinfo, store_session_key from pywe_storage import RedisStorage from TimeConvert import TimeConvert as tc from account.models import UserInfo from statistic.models import RegisterStatisticInfo from utils.error.errno_utils import UserStatusCode from utils.redis.connect import r from utils.redis.rprofile import set_profile_info WECHAT = settings.WECHAT @logit @transaction.atomic def get_userinfo_api(request): brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID) wxcfg = WECHAT.get('MINIAPP', {}) appid = wxcfg.get('appID') secret = wxcfg.get('appsecret') code = request.POST.get('code', '') encryptedData = request.POST.get('encryptedData', '') iv = request.POST.get('iv', '') # {u'avatarUrl': u'http://wx.qlogo.cn/mmopen/vi_32/aSKcBBPpibyKNicHNTMM0qJVh8Kjgiak2AHWr8MHM4WgMEm7GFhsf8OYrySdbvAMvTsw3mo8ibKicsnfN5pRjl1p8HQ/0', # u'city': u'Guangzhou', # u'country': u'CN', # u'gender': 1, # u'language': u'zh_CN', # u'nickName': u'Band', # u'openId': u'oGZUI0egBJY1zhBYw2KhdUfwVJJE', # u'province': u'Guangdong', # u'unionId': u'ocMvos6NjeKLIBqg5Mr9QjxrP1FA', # u'watermark': {u'appid': u'wx4f4bc4dec97d474b', u'timestamp': 1477314187}} session_key = get_session_key(appid=appid, secret=secret, code=code) # Get Userinfo userinfo = get_userinfo(appid=appid, secret=secret, code=code, session_key=session_key, encryptedData=encryptedData, iv=iv) # Get or Create User user, created = UserInfo.objects.select_for_update().get_or_create(brand_id=brand_id, unionid=userinfo.get('unionId', '')) # Set User_id if created: user.user_id = CurtailUUID.uuid(UserInfo, 'user_id') # 注册用户统计 rsi, _ = RegisterStatisticInfo.objects.select_for_update().get_or_create( brand_id=brand_id, ymd=int(tc.local_string(format='%Y%m%d')), ) rsi.num += 1 rsi.save() # Set User Key's Value user.user_from = UserInfo.MINIAPP_USER user.unionid = userinfo.get('unionId', '') user.openid_miniapp = userinfo.get('openId', '') user.sex = userinfo.get('gender', '') user.nickname = userinfo.get('nickName', '') user.avatar = userinfo.get('avatarUrl', '') user.country = userinfo.get('country', '') user.province = userinfo.get('province', '') user.city = userinfo.get('city', '') user.user_status = UserInfo.ACTIVATED user.signup_ip = client_ip(request) user.signup_at = tc.utc_datetime() user.save() # Store Userinfo set_profile_info(user) # Store SessionKey store_session_key(appid=appid, secret=secret, session_key=session_key, unid=user.user_id, storage=RedisStorage(r)) # Just for compatible because of store session_key has changed store_session_key(appid=appid, secret=secret, session_key=session_key, unid='', storage=RedisStorage(r)) return response(200, 'Mini App Login Success', u'微信小程序登录成功', user.brandata(brand_id=brand_id)) @logit(res=True) @transaction.atomic def mini_login_api(request): brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID) wxcfg = WECHAT.get('MINIAPP', {}) appid = wxcfg.get('appID') secret = wxcfg.get('appsecret') code = request.POST.get('code', '') # // 正常返回的JSON数据包 # { # "openid": "OPENID", # "session_key": "SESSIONKEY", # } # # // 满足UnionID返回条件时,返回的JSON数据包 # { # "openid": "OPENID", # "session_key": "SESSIONKEY", # "unionid": "UNIONID" # } # // 错误时返回JSON数据包(示例为Code无效) # { # "errcode": 40029, # "errmsg": "invalid code" # } session_info = get_session_info(appid=appid, secret=secret, code=code) session_key = session_info.get('session_key', '') unionid = session_info.get('unionid', '') openid = session_info.get('openid', '') # Get or Create User user, created = UserInfo.objects.select_for_update().get_or_create(brand_id=brand_id, openid_miniapp=openid) # Set User_id if created: user.user_id = CurtailUUID.uuid(UserInfo, 'user_id') # 注册用户统计 rsi, _ = RegisterStatisticInfo.objects.select_for_update().get_or_create( brand_id=brand_id, ymd=int(tc.local_string(format='%Y%m%d')), ) rsi.num += 1 rsi.save() # Set User Key's Value user.user_from = UserInfo.MINIAPP_USER if unionid: user.unionid = unionid user.user_status = UserInfo.ACTIVATED user.signup_ip = client_ip(request) user.signup_at = tc.utc_datetime() user.save() # Store Userinfo set_profile_info(user) # Store SessionKey store_session_key(appid=appid, secret=secret, session_key=session_key, unid=user.user_id, storage=RedisStorage(r)) # Just for compatible because of store session_key has changed store_session_key(appid=appid, secret=secret, session_key=session_key, unid='', storage=RedisStorage(r)) return response(200, 'Mini App Login Success', u'微信小程序登录成功', user.brandata(brand_id=brand_id)) @logit @transaction.atomic def get_userinfo_api2(request): brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID) user_id = request.POST.get('user_id', '') wxcfg = WECHAT.get('MINIAPP', {}) appid = wxcfg.get('appID') secret = wxcfg.get('appsecret') encryptedData = request.POST.get('encryptedData', '') iv = request.POST.get('iv', '') try: user = UserInfo.objects.get(user_id=user_id, status=True) except UserInfo.DoesNotExist: return response(UserStatusCode.USER_NOT_FOUND) # {u'avatarUrl': u'http://wx.qlogo.cn/mmopen/vi_32/aSKcBBPpibyKNicHNTMM0qJVh8Kjgiak2AHWr8MHM4WgMEm7GFhsf8OYrySdbvAMvTsw3mo8ibKicsnfN5pRjl1p8HQ/0', # u'city': u'Guangzhou', # u'country': u'CN', # u'gender': 1, # u'language': u'zh_CN', # u'nickName': u'Band', # u'openId': u'oGZUI0egBJY1zhBYw2KhdUfwVJJE', # u'province': u'Guangdong', # u'unionId': u'ocMvos6NjeKLIBqg5Mr9QjxrP1FA', # u'watermark': {u'appid': u'wx4f4bc4dec97d474b', u'timestamp': 1477314187}} session_key = get_session_key(appid=appid, secret=secret, unid=user_id, storage=RedisStorage(r)) # Get Userinfo userinfo = get_userinfo(appid=appid, secret=secret, session_key=session_key, encryptedData=encryptedData, iv=iv) # Set User Key's Value user.unionid = userinfo.get('unionId', '') user.openid_miniapp = userinfo.get('openId', '') user.sex = userinfo.get('gender', '') user.nickname = userinfo.get('nickName', '') user.avatar = userinfo.get('avatarUrl', '') user.country = userinfo.get('country', '') user.province = userinfo.get('province', '') user.city = userinfo.get('city', '') user.save() # Store Userinfo set_profile_info(user) return response(200, 'Mini App Get Userinfo Success', u'微信小程序获取用户信息成功', user.brandata(brand_id=brand_id)) @logit @transaction.atomic def membercard_extradata(request): wxcfg = WECHAT.get('JSAPI', {}) appid = wxcfg.get('appID') secret = wxcfg.get('appsecret') extraData = get_miniapp_extraData(settings.MEMBER_CARD_ID, outer_str='miniapp', appid=appid, secret=secret, storage=RedisStorage(r)) return response(200, 'Get extraData Success', u'获取 extraData 成功', extraData)