>BIN simditor/static/simditor/images/emoji/dog.png
@@ -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', 'nickname', 'phone', 'unionid', 'openid', 'openid_miniapp', 'location', 'balance', 'user_status', 'test_user', 'status', 'created_at', 'updated_at') |
|
11 |
+ list_display = ('user_id', 'nickname', 'phone', 'unionid', 'openid', 'openid_miniapp', 'location', 'balance', 'integral', 'freeze_integral', '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') |
@@ -0,0 +1,35 @@ |
||
1 |
+# -*- coding: utf-8 -*- |
|
2 |
+# Generated by Django 1.11.26 on 2019-11-19 05:48 |
|
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 |
+ ('account', '0036_auto_20190826_1537'), |
|
12 |
+ ] |
|
13 |
+ |
|
14 |
+ operations = [ |
|
15 |
+ migrations.AddField( |
|
16 |
+ model_name='userinfo', |
|
17 |
+ name='freeze_integral', |
|
18 |
+ field=models.IntegerField(default=0, help_text='\u4f1a\u5458\u51bb\u7ed3\u79ef\u5206', verbose_name='freeze_integral'), |
|
19 |
+ ), |
|
20 |
+ migrations.AddField( |
|
21 |
+ model_name='userinfo', |
|
22 |
+ name='integral', |
|
23 |
+ field=models.IntegerField(default=0, help_text='\u4f1a\u5458\u79ef\u5206', verbose_name='integral'), |
|
24 |
+ ), |
|
25 |
+ migrations.AddField( |
|
26 |
+ model_name='userinfo', |
|
27 |
+ name='level', |
|
28 |
+ field=models.IntegerField(choices=[(0, '\u975e\u4f1a\u5458'), (1, 'LRC\u4f1a\u5458'), (2, '\u94f6\u5361\u4f1a\u5458'), (3, '\u91d1\u5361\u4f1a\u5458'), (4, '\u767d\u91d1\u5361\u4f1a\u5458'), (5, '\u9ed1\u91d1\u5361\u4f1a\u5458')], default=0, help_text='\u4f1a\u5458\u7b49\u7ea7', verbose_name='level'), |
|
29 |
+ ), |
|
30 |
+ migrations.AddField( |
|
31 |
+ model_name='userinfo', |
|
32 |
+ name='shots_num', |
|
33 |
+ field=models.IntegerField(default=0, help_text='\u4e3b\u6301\u955c\u5934\u6570', verbose_name='shots_num'), |
|
34 |
+ ), |
|
35 |
+ ] |
@@ -290,6 +290,22 @@ class UserInfo(BaseModelMixin, LensmanTypeBoolMixin): |
||
290 | 290 |
(FEMALE, u'女'), |
291 | 291 |
) |
292 | 292 |
|
293 |
+ MEMBER_NO = 0 |
|
294 |
+ MEMBER_LRC = 1 |
|
295 |
+ MEMBER_SILVER = 2 |
|
296 |
+ MEMBER_GOLD = 3 |
|
297 |
+ MEMBER_WHITE_GOLD = 4 |
|
298 |
+ MEMBER_BLACK_GOLD = 5 |
|
299 |
+ |
|
300 |
+ LEVEL_TUPLE = ( |
|
301 |
+ (MEMBER_NO, u'非会员'), |
|
302 |
+ (MEMBER_LRC, u'LRC会员'), |
|
303 |
+ (MEMBER_SILVER, u'银卡会员'), |
|
304 |
+ (MEMBER_GOLD, u'金卡会员'), |
|
305 |
+ (MEMBER_WHITE_GOLD, u'白金卡会员'), |
|
306 |
+ (MEMBER_BLACK_GOLD, u'黑金卡会员'), |
|
307 |
+ ) |
|
308 |
+ |
|
293 | 309 |
user_id = models.CharField(_(u'user_id'), max_length=32, blank=True, null=True, help_text=u'用户唯一标识', db_index=True, unique=True) |
294 | 310 |
|
295 | 311 |
user_from = models.IntegerField(_(u'user_from'), choices=USER_FROM, default=APP_USER, help_text=u'用户来源') |
@@ -341,6 +357,13 @@ class UserInfo(BaseModelMixin, LensmanTypeBoolMixin): |
||
341 | 357 |
|
342 | 358 |
test_user = models.BooleanField(_(u'test_user'), default=False, help_text=_(u'是否为测试用户'), db_index=True) |
343 | 359 |
|
360 |
+ # 会员信息 |
|
361 |
+ integral = models.IntegerField(_(u'integral'), default=0, help_text=u'会员积分') |
|
362 |
+ freeze_integral = models.IntegerField(_(u'freeze_integral'), default=0, help_text=u'会员冻结积分') |
|
363 |
+ |
|
364 |
+ shots_num = models.IntegerField(_(u'shots_num'), default=0, help_text=u'主持镜头数') |
|
365 |
+ level = models.IntegerField(_(u'level'), choices=LEVEL_TUPLE, default=MEMBER_NO, help_text=u'会员等级') |
|
366 |
+ |
|
344 | 367 |
class Meta: |
345 | 368 |
verbose_name = _(u'userinfo') |
346 | 369 |
verbose_name_plural = _(u'userinfo') |
@@ -349,6 +372,10 @@ class UserInfo(BaseModelMixin, LensmanTypeBoolMixin): |
||
349 | 372 |
return unicode(self.pk) |
350 | 373 |
|
351 | 374 |
@property |
375 |
+ def final_integral(self): |
|
376 |
+ return self.integral + self.freeze_integral |
|
377 |
+ |
|
378 |
+ @property |
|
352 | 379 |
def final_nickname(self): |
353 | 380 |
if self.user_from == self.APP_USER: |
354 | 381 |
return self.username |
@@ -0,0 +1,200 @@ |
||
1 |
+# -*- coding: utf-8 -*- |
|
2 |
+ |
|
3 |
+from __future__ import division |
|
4 |
+ |
|
5 |
+from django.conf import settings |
|
6 |
+from django_logit import logit |
|
7 |
+from django_response import response |
|
8 |
+from paginator import pagination |
|
9 |
+ |
|
10 |
+from account.models import UserInfo |
|
11 |
+from member.models import GoodsInfo, MemberActivityInfo, RightInfo |
|
12 |
+from utils.error.errno_utils import UserStatusCode |
|
13 |
+from utils.redis.rshot import get_shot_member_data |
|
14 |
+ |
|
15 |
+ |
|
16 |
+@logit |
|
17 |
+def member(request): |
|
18 |
+ brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID) |
|
19 |
+ user_id = request.POST.get('user_id', '') |
|
20 |
+ |
|
21 |
+ # 校验用户是否存在 |
|
22 |
+ try: |
|
23 |
+ user = UserInfo.objects.get(user_id=user_id) |
|
24 |
+ except UserInfo.DoesNotExist: |
|
25 |
+ return response(UserStatusCode.USER_NOT_FOUND) |
|
26 |
+ |
|
27 |
+ rights = RightInfo.objects.filter(status=True).order_by('position') |
|
28 |
+ rights = [right.data for right in rights] |
|
29 |
+ |
|
30 |
+ goods = GoodsInfo.objects.filter(status=True).order_by('position') |
|
31 |
+ goods = [good.data for good in goods] |
|
32 |
+ |
|
33 |
+ return response(200, data={ |
|
34 |
+ 'nickname': user.final_nickname, |
|
35 |
+ 'avatar': user.avatar, |
|
36 |
+ 'integral': user.integral, |
|
37 |
+ 'freeze_integral': user.freeze_integral, |
|
38 |
+ 'final_integral': user.final_integral, |
|
39 |
+ 'shots_num': user.shots_num, |
|
40 |
+ 'level': user.level, |
|
41 |
+ 'rights': rights, |
|
42 |
+ 'goods': goods, |
|
43 |
+ }) |
|
44 |
+ |
|
45 |
+ |
|
46 |
+@logit |
|
47 |
+def rights(request): |
|
48 |
+ brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID) |
|
49 |
+ user_id = request.POST.get('user_id', '') |
|
50 |
+ level = request.POST.get('level', '') |
|
51 |
+ |
|
52 |
+ # 校验用户是否存在 |
|
53 |
+ try: |
|
54 |
+ user = UserInfo.objects.get(user_id=user_id) |
|
55 |
+ except UserInfo.DoesNotExist: |
|
56 |
+ return response(UserStatusCode.USER_NOT_FOUND) |
|
57 |
+ |
|
58 |
+ rights = RightInfo.objects.filter(status=True).order_by('position') |
|
59 |
+ rights = [right.data for right in rights] |
|
60 |
+ |
|
61 |
+ return response(200, data={ |
|
62 |
+ 'nickname': user.final_nickname, |
|
63 |
+ 'avatar': user.avatar, |
|
64 |
+ 'integral': user.integral, |
|
65 |
+ 'freeze_integral': user.freeze_integral, |
|
66 |
+ 'final_integral': user.final_integral, |
|
67 |
+ 'shots_num': user.shots_num, |
|
68 |
+ 'level': user.level, |
|
69 |
+ 'rights': rights, |
|
70 |
+ }) |
|
71 |
+ |
|
72 |
+ |
|
73 |
+@logit |
|
74 |
+def right_detail(request): |
|
75 |
+ brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID) |
|
76 |
+ user_id = request.POST.get('user_id', '') |
|
77 |
+ right_id = request.POST.get('right_id', '') |
|
78 |
+ |
|
79 |
+ try: |
|
80 |
+ right = RightInfo.objects.get(right_id=right_id) |
|
81 |
+ except RightInfo.DoesNotExist: |
|
82 |
+ return response() |
|
83 |
+ |
|
84 |
+ return response(200, data={ |
|
85 |
+ 'right': right.data, |
|
86 |
+ }) |
|
87 |
+ |
|
88 |
+ |
|
89 |
+@logit |
|
90 |
+def goods(request): |
|
91 |
+ brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID) |
|
92 |
+ user_id = request.POST.get('user_id', '') |
|
93 |
+ |
|
94 |
+ # 校验用户是否存在 |
|
95 |
+ try: |
|
96 |
+ user = UserInfo.objects.get(user_id=user_id) |
|
97 |
+ except UserInfo.DoesNotExist: |
|
98 |
+ return response(UserStatusCode.USER_NOT_FOUND) |
|
99 |
+ |
|
100 |
+ raw_goods = GoodsInfo.objects.filter(status=True).order_by('position') |
|
101 |
+ banners = goods = [] |
|
102 |
+ for good in raw_goods: |
|
103 |
+ if good.is_slider: |
|
104 |
+ banners.append(good.data) |
|
105 |
+ else: |
|
106 |
+ goods.append(good.data) |
|
107 |
+ |
|
108 |
+ return response(200, data={ |
|
109 |
+ 'nickname': user.final_nickname, |
|
110 |
+ 'avatar': user.avatar, |
|
111 |
+ 'integral': user.integral, |
|
112 |
+ 'freeze_integral': user.freeze_integral, |
|
113 |
+ 'final_integral': user.final_integral, |
|
114 |
+ 'shots_num': user.shots_num, |
|
115 |
+ 'level': user.level, |
|
116 |
+ 'banners': banners, |
|
117 |
+ 'goods': goods, |
|
118 |
+ }) |
|
119 |
+ |
|
120 |
+ |
|
121 |
+@logit |
|
122 |
+def good_detail(request): |
|
123 |
+ brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID) |
|
124 |
+ user_id = request.POST.get('user_id', '') |
|
125 |
+ good_id = request.POST.get('good_id', '') |
|
126 |
+ |
|
127 |
+ # 校验用户是否存在 |
|
128 |
+ try: |
|
129 |
+ user = UserInfo.objects.get(user_id=user_id) |
|
130 |
+ except UserInfo.DoesNotExist: |
|
131 |
+ return response(UserStatusCode.USER_NOT_FOUND) |
|
132 |
+ |
|
133 |
+ try: |
|
134 |
+ good = GoodsInfo.objects.get(good_id=good_id) |
|
135 |
+ except GoodsInfo.DoesNotExist: |
|
136 |
+ return response() |
|
137 |
+ |
|
138 |
+ return response(200, data={ |
|
139 |
+ 'nickname': user.final_nickname, |
|
140 |
+ 'avatar': user.avatar, |
|
141 |
+ 'integral': user.integral, |
|
142 |
+ 'freeze_integral': user.freeze_integral, |
|
143 |
+ 'final_integral': user.final_integral, |
|
144 |
+ 'shots_num': user.shots_num, |
|
145 |
+ 'level': user.level, |
|
146 |
+ 'good': good.data, |
|
147 |
+ }) |
|
148 |
+ |
|
149 |
+ |
|
150 |
+@logit |
|
151 |
+def integrals(request): |
|
152 |
+ brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID) |
|
153 |
+ |
|
154 |
+ return response(200, data={ |
|
155 |
+ 'shots_types': get_shot_member_data(), |
|
156 |
+ 'enable_photo_upvote_integral': True, |
|
157 |
+ 'photo_upvote_integrals': { |
|
158 |
+ 'headers': ['排名', '日', '周', '月'], |
|
159 |
+ 'ranks': [ |
|
160 |
+ ['第1名', '10', '20', '30'], |
|
161 |
+ ['第2名', '5', '10', '15'], |
|
162 |
+ ['第3名', '3', '6', '9'], |
|
163 |
+ ['第4-10名', '1', '2', '3'], |
|
164 |
+ ] |
|
165 |
+ }, |
|
166 |
+ 'enable_activity_integral': True, |
|
167 |
+ }) |
|
168 |
+ |
|
169 |
+ |
|
170 |
+@logit |
|
171 |
+def activity_list(request): |
|
172 |
+ brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID) |
|
173 |
+ |
|
174 |
+ raw_activitys = MemberActivityInfo.objects.filter(status=True).order_by('position') |
|
175 |
+ banners = activitys = [] |
|
176 |
+ for act in raw_activitys: |
|
177 |
+ if act.is_slider: |
|
178 |
+ banners.append(act.data) |
|
179 |
+ else: |
|
180 |
+ goods.append(act.data) |
|
181 |
+ |
|
182 |
+ return response(200, data={ |
|
183 |
+ 'banners': banners, |
|
184 |
+ 'activitys': activitys, |
|
185 |
+ }) |
|
186 |
+ |
|
187 |
+ |
|
188 |
+@logit |
|
189 |
+def activity_detail(request): |
|
190 |
+ brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID) |
|
191 |
+ activity_id = request.POST.get('activity_id') |
|
192 |
+ |
|
193 |
+ try: |
|
194 |
+ act = MemberActivityInfo.objects.get(pk=activity_id, status=True) |
|
195 |
+ except MemberActivityInfo.DoesNotExist: |
|
196 |
+ return response() |
|
197 |
+ |
|
198 |
+ return response(200, data={ |
|
199 |
+ 'activity': act.data, |
|
200 |
+ }) |
@@ -5,8 +5,8 @@ from django_file_upload import views as file_views |
||
5 | 5 |
|
6 | 6 |
from account import tourguide_views |
7 | 7 |
from account import views as account_views |
8 |
-from api import (admin_views, clerk_views, distributor_views, encrypt_views, mch_views, model_views, operator_views, |
|
9 |
- sr_views) |
|
8 |
+from api import (admin_views, clerk_views, distributor_views, encrypt_views, mch_views, member_views, model_views, |
|
9 |
+ operator_views, sr_views) |
|
10 | 10 |
from box import views as box_views |
11 | 11 |
from geo import views as geo_views |
12 | 12 |
from group import (groupuser_views, lensman_views, tourguidegroup_views, tourguidegroupadmin_views, |
@@ -298,3 +298,22 @@ urlpatterns += [ |
||
298 | 298 |
urlpatterns += [ |
299 | 299 |
url(r'^supersr/sr/tj$', sales_views.supersr_sr_tj, name='supersr_sr_tj'), |
300 | 300 |
] |
301 |
+ |
|
302 |
+urlpatterns += [ |
|
303 |
+ url(r'^member$', member_views.member, name='member'), |
|
304 |
+ |
|
305 |
+ url(r'^member/rights$', member_views.rights, name='member_rights'), |
|
306 |
+ url(r'^member/right/detail$', member_views.right_detail, name='member_right_detail'), |
|
307 |
+ url(r'^member/goods$', member_views.goods, name='member_goods'), |
|
308 |
+ url(r'^member/good/detail$', member_views.good_detail, name='member_good_detail'), |
|
309 |
+ url(r'^member/integrals$', member_views.integrals, name='member_integrals'), |
|
310 |
+ |
|
311 |
+ url(r'^member/activity/list$', member_views.activity_list, name='member_activity_list'), |
|
312 |
+ url(r'^member/activity/detail$', member_views.activity_detail, name='member_activity_detail'), |
|
313 |
+ |
|
314 |
+ url(r'^rights$', member_views.rights, name='rights'), |
|
315 |
+ url(r'^right/detail$', member_views.right_detail, name='right_detail'), |
|
316 |
+ url(r'^goods$', member_views.goods, name='goods'), |
|
317 |
+ url(r'^good/detail$', member_views.good_detail, name='good_detail'), |
|
318 |
+ url(r'^integrals$', member_views.integrals, name='integrals'), |
|
319 |
+] |
@@ -0,0 +1,25 @@ |
||
1 |
+# -*- coding: utf-8 -*- |
|
2 |
+# Generated by Django 1.11.26 on 2019-11-19 05:48 |
|
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 |
+ ('integral', '0010_auto_20190909_1456'), |
|
12 |
+ ] |
|
13 |
+ |
|
14 |
+ operations = [ |
|
15 |
+ migrations.AddField( |
|
16 |
+ model_name='saleclerksubmitloginfo', |
|
17 |
+ name='has_scan', |
|
18 |
+ field=models.BooleanField(db_index=True, default=False, help_text='\u662f\u5426\u88ab\u6d88\u8d39\u8005\u626b\u8fc7', verbose_name='has_scan'), |
|
19 |
+ ), |
|
20 |
+ migrations.AddField( |
|
21 |
+ model_name='saleclerksubmitloginfo', |
|
22 |
+ name='trackingNo', |
|
23 |
+ field=models.CharField(blank=True, help_text='\u5feb\u9012\u5355\u53f7', max_length=32, null=True, verbose_name='trackingNo'), |
|
24 |
+ ), |
|
25 |
+ ] |
@@ -49,6 +49,7 @@ INSTALLED_APPS = ( |
||
49 | 49 |
'django_rlog', |
50 | 50 |
'django_we', |
51 | 51 |
'corsheaders', |
52 |
+ 'simditor', |
|
52 | 53 |
'api', |
53 | 54 |
'account', |
54 | 55 |
'box', |
@@ -58,6 +59,7 @@ INSTALLED_APPS = ( |
||
58 | 59 |
'integral', |
59 | 60 |
'logs', |
60 | 61 |
'mch', |
62 |
+ 'member', |
|
61 | 63 |
'message', |
62 | 64 |
'miniapp', |
63 | 65 |
'operation', |
@@ -346,6 +348,25 @@ CORS_ORIGIN_WHITELIST = ( |
||
346 | 348 |
) |
347 | 349 |
CORS_ALLOW_CREDENTIALS = True |
348 | 350 |
|
351 |
+# 富文本编辑器 |
|
352 |
+SIMDITOR_UPLOAD_PATH = 'uploads/' |
|
353 |
+SIMDITOR_TOOLBAR = [ |
|
354 |
+ 'markdown', 'title', 'bold', 'italic', 'underline', 'strikethrough', 'fontScale', |
|
355 |
+ 'color', '|', 'ol', 'ul', 'blockquote', 'code', 'table', '|', 'link', |
|
356 |
+ 'image', 'hr', '|', 'indent', 'outdent', 'alignment', 'checklist', 'fullscreen', 'emoji' |
|
357 |
+] |
|
358 |
+SIMDITOR_CONFIGS = { |
|
359 |
+ 'toolbar': SIMDITOR_TOOLBAR, |
|
360 |
+ 'upload': { |
|
361 |
+ 'url': '/simditor/upload/', |
|
362 |
+ 'fileKey': 'upload', |
|
363 |
+ 'image_size': 1024 * 1024 * 4 # max image size 4MB |
|
364 |
+ }, |
|
365 |
+ 'emoji': { |
|
366 |
+ 'imagePath': '/static/simditor/images/emoji/' |
|
367 |
+ } |
|
368 |
+} |
|
369 |
+ |
|
349 | 370 |
# 错误信息邮件设置 |
350 | 371 |
# Email address that error messages come from. |
351 | 372 |
SERVER_EMAIL = 'kimi@pai.ai' |
@@ -10,6 +10,7 @@ from pysnippets.strsnippets import strip |
||
10 | 10 |
|
11 | 11 |
from mch.models import (ActivityInfo, AdministratorInfo, BrandInfo, ConsumeInfoSubmitLogInfo, DistributorInfo, |
12 | 12 |
LatestAppInfo, LatestAppScreenInfo, ModelInfo, OperatorInfo, SaleclerkInfo) |
13 |
+from utils.redis.rshot import update_shot_member_data |
|
13 | 14 |
|
14 | 15 |
|
15 | 16 |
class AdministratorInfoAdmin(admin.ModelAdmin): |
@@ -64,7 +65,7 @@ class BrandInfoAdmin(admin.ModelAdmin): |
||
64 | 65 |
|
65 | 66 |
class ModelInfoAdmin(admin.ModelAdmin): |
66 | 67 |
list_display = ('brand_id', 'brand_name', 'jancode', 'model_id', 'model_name', 'model_uni_name', 'model_full_name', 'model_descr', 'category', 'warehouse', 'image', 'url', 'image2', 'factory_yuan', 'integral', 'position', 'display', 'status', 'created_at', 'updated_at') |
67 |
- list_filter = ('brand_name', 'category', 'warehouse', 'display', 'status') |
|
68 |
+ list_filter = ('brand_name', 'category', 'warehouse', 'shot_type_id', 'display', 'status') |
|
68 | 69 |
readonly_fields = ('brand_name', 'factory_fee') |
69 | 70 |
search_fields = ('brand_id', 'brand_name', 'jancode', 'model_id', 'model_name', 'model_uni_name', 'model_full_name', 'model_descr', 'category', 'warehouse') |
70 | 71 |
|
@@ -80,6 +81,12 @@ class ModelInfoAdmin(admin.ModelAdmin): |
||
80 | 81 |
|
81 | 82 |
obj.save() |
82 | 83 |
|
84 |
+ update_shot_member_data() |
|
85 |
+ |
|
86 |
+ def delete_model(self, request, obj): |
|
87 |
+ obj.delete() |
|
88 |
+ update_shot_member_data() |
|
89 |
+ |
|
83 | 90 |
|
84 | 91 |
class ModelImageInfoAdmin(admin.ModelAdmin): |
85 | 92 |
list_display = ('model_id', 'model_name', 'image', 'url', 'position', 'status', 'created_at', 'updated_at') |
@@ -0,0 +1,36 @@ |
||
1 |
+# -*- coding: utf-8 -*- |
|
2 |
+# Generated by Django 1.11.26 on 2019-11-19 05:48 |
|
3 |
+from __future__ import unicode_literals |
|
4 |
+ |
|
5 |
+from django.db import migrations, models |
|
6 |
+import django_models_ext.fileext |
|
7 |
+ |
|
8 |
+ |
|
9 |
+class Migration(migrations.Migration): |
|
10 |
+ |
|
11 |
+ dependencies = [ |
|
12 |
+ ('mch', '0038_auto_20190826_1625'), |
|
13 |
+ ] |
|
14 |
+ |
|
15 |
+ operations = [ |
|
16 |
+ migrations.AddField( |
|
17 |
+ model_name='modelinfo', |
|
18 |
+ name='shot_member_image', |
|
19 |
+ field=models.ImageField(blank=True, help_text='\u955c\u5934\u4f1a\u5458\u56fe\u7247', null=True, upload_to=django_models_ext.fileext.upload_path, verbose_name='shot_member_image'), |
|
20 |
+ ), |
|
21 |
+ migrations.AddField( |
|
22 |
+ model_name='modelinfo', |
|
23 |
+ name='shot_member_integral', |
|
24 |
+ field=models.IntegerField(default=0, help_text='\u955c\u5934\u4f1a\u5458\u79ef\u5206', verbose_name='shot_member_integral'), |
|
25 |
+ ), |
|
26 |
+ migrations.AddField( |
|
27 |
+ model_name='modelinfo', |
|
28 |
+ name='shot_type_id', |
|
29 |
+ field=models.CharField(blank=True, db_index=True, help_text='\u955c\u5934\u7c7b\u578b\u552f\u4e00\u6807\u8bc6', max_length=32, null=True, verbose_name='shot_type_id'), |
|
30 |
+ ), |
|
31 |
+ migrations.AddField( |
|
32 |
+ model_name='saleclerkinfo', |
|
33 |
+ name='is_online_sales', |
|
34 |
+ field=models.BooleanField(db_index=True, default=False, help_text='\u662f\u5426\u4e3a\u7f51\u9500', verbose_name='is_online_sales'), |
|
35 |
+ ), |
|
36 |
+ ] |
@@ -161,6 +161,10 @@ class ModelInfo(BaseModelMixin): |
||
161 | 161 |
|
162 | 162 |
is_important = models.BooleanField(_(u'is_important'), default=False, help_text=_(u'是否重要型号'), db_index=True) |
163 | 163 |
|
164 |
+ shot_type_id = models.CharField(_(u'shot_type_id'), max_length=32, blank=True, null=True, help_text=u'镜头类型唯一标识', db_index=True) |
|
165 |
+ shot_member_integral = models.IntegerField(_(u'shot_member_integral'), default=0, help_text=u'镜头会员积分') |
|
166 |
+ shot_member_image = models.ImageField(_(u'shot_member_image'), upload_to=upload_path, blank=True, null=True, help_text=u'镜头会员图片') |
|
167 |
+ |
|
164 | 168 |
class Meta: |
165 | 169 |
verbose_name = _(u'型号信息') |
166 | 170 |
verbose_name_plural = _(u'型号信息') |
@@ -185,6 +189,14 @@ class ModelInfo(BaseModelMixin): |
||
185 | 189 |
return upload_file_url(self.image2) |
186 | 190 |
|
187 | 191 |
@property |
192 |
+ def shot_member_image_path(self): |
|
193 |
+ return upload_file_path(self.shot_member_image) |
|
194 |
+ |
|
195 |
+ @property |
|
196 |
+ def shot_member_image_url(self): |
|
197 |
+ return upload_file_url(self.shot_member_image) |
|
198 |
+ |
|
199 |
+ @property |
|
188 | 200 |
def data(self): |
189 | 201 |
return { |
190 | 202 |
'jancode': self.jancode, |
@@ -228,6 +240,15 @@ class ModelInfo(BaseModelMixin): |
||
228 | 240 |
|
229 | 241 |
fulldata = admindata |
230 | 242 |
|
243 |
+ @property |
|
244 |
+ def shot_member_data(self): |
|
245 |
+ return { |
|
246 |
+ 'shot_id': self.model_id, |
|
247 |
+ 'shot_name': self.model_name, |
|
248 |
+ 'shot_image': self.shot_member_image_url, |
|
249 |
+ 'integral': self.shot_member_integral, |
|
250 |
+ } |
|
251 |
+ |
|
231 | 252 |
|
232 | 253 |
class ModelImageInfo(BaseModelMixin): |
233 | 254 |
model_id = models.CharField(_(u'model_id'), max_length=32, blank=True, null=True, help_text=u'型号唯一标识', db_index=True) |
@@ -0,0 +1,38 @@ |
||
1 |
+# -*- coding: utf-8 -*- |
|
2 |
+ |
|
3 |
+from django.contrib import admin |
|
4 |
+ |
|
5 |
+from member.models import GoodsInfo, MemberActivityInfo, ShotTypeInfo, RightInfo |
|
6 |
+from utils.redis.rshot import update_shot_member_data |
|
7 |
+ |
|
8 |
+ |
|
9 |
+class GoodsInfoAdmin(admin.ModelAdmin): |
|
10 |
+ list_display = ('good_id', 'good_type', 'title', 'desc', 'image', 'is_slider', 'slider_image', 'integral', 'fee', 'minlevel', 'position', 'status', 'created_at', 'updated_at') |
|
11 |
+ list_filter = ('is_slider', 'status') |
|
12 |
+ |
|
13 |
+ |
|
14 |
+class RightInfoAdmin(admin.ModelAdmin): |
|
15 |
+ list_display = ('right_id', 'icon', 'title', 'subtitle', 'detail', 'minlevel', 'position', 'status', 'created_at', 'updated_at') |
|
16 |
+ |
|
17 |
+ |
|
18 |
+class ShotTypeInfoAdmin(admin.ModelAdmin): |
|
19 |
+ list_display = ('shot_type_id', 'shot_type_name', 'position', 'status', 'created_at', 'updated_at') |
|
20 |
+ |
|
21 |
+ def save_model(self, request, obj, form, change): |
|
22 |
+ obj.save() |
|
23 |
+ update_shot_member_data() |
|
24 |
+ |
|
25 |
+ def delete_model(self, request, obj): |
|
26 |
+ obj.delete() |
|
27 |
+ update_shot_member_data() |
|
28 |
+ |
|
29 |
+ |
|
30 |
+class MemberActivityInfoAdmin(admin.ModelAdmin): |
|
31 |
+ list_display = ('title', 'subtitle', 'date', 'location', 'image', 'is_slider', 'slider_image', 'position', 'status', 'created_at', 'updated_at') |
|
32 |
+ list_filter = ('is_slider', 'status') |
|
33 |
+ |
|
34 |
+ |
|
35 |
+admin.site.register(GoodsInfo, GoodsInfoAdmin) |
|
36 |
+admin.site.register(RightInfo, RightInfoAdmin) |
|
37 |
+admin.site.register(ShotTypeInfo, ShotTypeInfoAdmin) |
|
38 |
+admin.site.register(MemberActivityInfo, MemberActivityInfoAdmin) |
@@ -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 MemberConfig(AppConfig): |
|
8 |
+ name = 'member' |
@@ -0,0 +1,104 @@ |
||
1 |
+# -*- coding: utf-8 -*- |
|
2 |
+# Generated by Django 1.11.26 on 2019-11-19 05:48 |
|
3 |
+from __future__ import unicode_literals |
|
4 |
+ |
|
5 |
+from django.db import migrations, models |
|
6 |
+import django_models_ext.fileext |
|
7 |
+import shortuuidfield.fields |
|
8 |
+import simditor.fields |
|
9 |
+ |
|
10 |
+ |
|
11 |
+class Migration(migrations.Migration): |
|
12 |
+ |
|
13 |
+ initial = True |
|
14 |
+ |
|
15 |
+ dependencies = [ |
|
16 |
+ ] |
|
17 |
+ |
|
18 |
+ operations = [ |
|
19 |
+ migrations.CreateModel( |
|
20 |
+ name='GoodsInfo', |
|
21 |
+ fields=[ |
|
22 |
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
|
23 |
+ ('status', models.BooleanField(db_index=True, default=True, help_text='Status', verbose_name='status')), |
|
24 |
+ ('created_at', models.DateTimeField(auto_now_add=True, help_text='Create Time', verbose_name='created_at')), |
|
25 |
+ ('updated_at', models.DateTimeField(auto_now=True, help_text='Update Time', verbose_name='updated_at')), |
|
26 |
+ ('good_id', shortuuidfield.fields.ShortUUIDField(blank=True, db_index=True, editable=False, help_text='\u5546\u54c1\u552f\u4e00\u6807\u8bc6', max_length=22, null=True, unique=True)), |
|
27 |
+ ('good_type', models.IntegerField(choices=[(0, '\u5b9e\u7269'), (1, '\u865a\u62df')], db_index=True, default=1, help_text='\u5546\u54c1\u7c7b\u578b', verbose_name='good_type')), |
|
28 |
+ ('title', models.CharField(blank=True, help_text='\u5546\u54c1\u540d\u79f0', max_length=255, null=True, verbose_name='title')), |
|
29 |
+ ('desc', simditor.fields.RichTextField(blank=True, help_text='\u5546\u54c1\u63cf\u8ff0', null=True, verbose_name='desc')), |
|
30 |
+ ('image', models.ImageField(blank=True, help_text='\u5546\u54c1\u56fe\u7247', null=True, upload_to=django_models_ext.fileext.upload_path, verbose_name='image')), |
|
31 |
+ ('is_slider', models.BooleanField(db_index=True, default=True, help_text='\u662f\u5426\u4e3a\u8f6e\u64ad\u5546\u54c1', verbose_name='is_slider')), |
|
32 |
+ ('slider_image', models.ImageField(blank=True, help_text='\u5546\u54c1\u8f6e\u64ad\u56fe\u7247', null=True, upload_to=django_models_ext.fileext.upload_path, verbose_name='slider_image')), |
|
33 |
+ ('integral', models.IntegerField(default=99999, help_text='\u5151\u6362\u6240\u9700\u79ef\u5206', verbose_name='integral')), |
|
34 |
+ ('fee', models.IntegerField(default=99999, help_text='\u5151\u6362\u9700\u989d\u5916\u652f\u4ed8\u91d1\u989d\uff0c\u5355\u4f4d\u5206', verbose_name='fee')), |
|
35 |
+ ('minlevel', models.IntegerField(default=0, help_text='\u5151\u6362\u6700\u4f4e\u4f1a\u5458\u7ea7\u522b', verbose_name='minlevel')), |
|
36 |
+ ('position', models.IntegerField(db_index=True, default=1, help_text='\u6392\u5e8f', verbose_name='position')), |
|
37 |
+ ], |
|
38 |
+ options={ |
|
39 |
+ 'verbose_name': '\u5546\u54c1\u4fe1\u606f', |
|
40 |
+ 'verbose_name_plural': '\u5546\u54c1\u4fe1\u606f', |
|
41 |
+ }, |
|
42 |
+ ), |
|
43 |
+ migrations.CreateModel( |
|
44 |
+ name='MemberActivityInfo', |
|
45 |
+ fields=[ |
|
46 |
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
|
47 |
+ ('status', models.BooleanField(db_index=True, default=True, help_text='Status', verbose_name='status')), |
|
48 |
+ ('created_at', models.DateTimeField(auto_now_add=True, help_text='Create Time', verbose_name='created_at')), |
|
49 |
+ ('updated_at', models.DateTimeField(auto_now=True, help_text='Update Time', verbose_name='updated_at')), |
|
50 |
+ ('title', models.CharField(blank=True, help_text='\u6d3b\u52a8\u540d\u79f0', max_length=255, null=True, verbose_name='title')), |
|
51 |
+ ('subtitle', models.CharField(blank=True, help_text='\u6d3b\u52a8\u4e8c\u7ea7\u540d\u79f0', max_length=255, null=True, verbose_name='subtitle')), |
|
52 |
+ ('date', models.DateField(blank=True, help_text='\u6d3b\u52a8\u65f6\u95f4', null=True, verbose_name='date')), |
|
53 |
+ ('location', models.CharField(blank=True, help_text='\u6d3b\u52a8\u5730\u70b9', max_length=255, null=True, verbose_name='location')), |
|
54 |
+ ('image', models.ImageField(blank=True, help_text='\u6d3b\u52a8\u5185\u5bb9\u56fe\u7247', null=True, upload_to=django_models_ext.fileext.upload_path, verbose_name='image')), |
|
55 |
+ ('cover', models.ImageField(blank=True, help_text='\u6d3b\u52a8\u5217\u8868\u56fe\u7247', null=True, upload_to=django_models_ext.fileext.upload_path, verbose_name='cover')), |
|
56 |
+ ('is_slider', models.BooleanField(db_index=True, default=True, help_text='\u662f\u5426\u4e3a\u8f6e\u64ad\u6d3b\u52a8', verbose_name='is_slider')), |
|
57 |
+ ('slider_image', models.ImageField(blank=True, help_text='\u6d3b\u52a8\u8f6e\u64ad\u56fe\u7247', null=True, upload_to=django_models_ext.fileext.upload_path, verbose_name='slider_image')), |
|
58 |
+ ('content_rich_text', simditor.fields.RichTextField(blank=True, help_text='\u6d3b\u52a8\u63cf\u8ff0', null=True, verbose_name='content_rich_text')), |
|
59 |
+ ('share_img_link', models.CharField(blank=True, help_text='\u6d3b\u52a8\u56fe\u7247\u5206\u4eab', max_length=255, null=True, verbose_name='share_img_link')), |
|
60 |
+ ('share_h5_link', models.CharField(blank=True, help_text='\u6d3b\u52a8H5\u5206\u4eab', max_length=255, null=True, verbose_name='share_h5_link')), |
|
61 |
+ ('position', models.IntegerField(db_index=True, default=1, help_text='\u6392\u5e8f', verbose_name='position')), |
|
62 |
+ ], |
|
63 |
+ options={ |
|
64 |
+ 'verbose_name': '\u4f1a\u5458\u6d3b\u52a8\u4fe1\u606f', |
|
65 |
+ 'verbose_name_plural': '\u4f1a\u5458\u6d3b\u52a8\u4fe1\u606f', |
|
66 |
+ }, |
|
67 |
+ ), |
|
68 |
+ migrations.CreateModel( |
|
69 |
+ name='RightInfo', |
|
70 |
+ fields=[ |
|
71 |
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
|
72 |
+ ('status', models.BooleanField(db_index=True, default=True, help_text='Status', verbose_name='status')), |
|
73 |
+ ('created_at', models.DateTimeField(auto_now_add=True, help_text='Create Time', verbose_name='created_at')), |
|
74 |
+ ('updated_at', models.DateTimeField(auto_now=True, help_text='Update Time', verbose_name='updated_at')), |
|
75 |
+ ('right_id', shortuuidfield.fields.ShortUUIDField(blank=True, db_index=True, editable=False, help_text='\u6743\u76ca\u552f\u4e00\u6807\u8bc6', max_length=22, null=True, unique=True)), |
|
76 |
+ ('icon', models.ImageField(blank=True, help_text='\u6743\u76ca\u56fe\u6807', null=True, upload_to=django_models_ext.fileext.upload_path, verbose_name='icon')), |
|
77 |
+ ('title', models.CharField(blank=True, help_text='\u6743\u76ca\u540d\u79f0', max_length=255, null=True, verbose_name='title')), |
|
78 |
+ ('subtitle', models.CharField(blank=True, help_text='\u6743\u76ca\u4e8c\u7ea7\u540d\u79f0', max_length=255, null=True, verbose_name='subtitle')), |
|
79 |
+ ('detail', simditor.fields.RichTextField(blank=True, help_text='\u6743\u76ca\u8be6\u60c5', null=True, verbose_name='detail')), |
|
80 |
+ ('minlevel', models.IntegerField(default=0, help_text='\u6743\u76ca\u6700\u4f4e\u4f1a\u5458\u7ea7\u522b', verbose_name='minlevel')), |
|
81 |
+ ('position', models.IntegerField(db_index=True, default=1, help_text='\u6392\u5e8f', verbose_name='position')), |
|
82 |
+ ], |
|
83 |
+ options={ |
|
84 |
+ 'verbose_name': '\u6743\u76ca\u4fe1\u606f', |
|
85 |
+ 'verbose_name_plural': '\u6743\u76ca\u4fe1\u606f', |
|
86 |
+ }, |
|
87 |
+ ), |
|
88 |
+ migrations.CreateModel( |
|
89 |
+ name='ShotTypeInfo', |
|
90 |
+ fields=[ |
|
91 |
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
|
92 |
+ ('status', models.BooleanField(db_index=True, default=True, help_text='Status', verbose_name='status')), |
|
93 |
+ ('created_at', models.DateTimeField(auto_now_add=True, help_text='Create Time', verbose_name='created_at')), |
|
94 |
+ ('updated_at', models.DateTimeField(auto_now=True, help_text='Update Time', verbose_name='updated_at')), |
|
95 |
+ ('shot_type_id', shortuuidfield.fields.ShortUUIDField(blank=True, db_index=True, editable=False, help_text='\u955c\u5934\u7c7b\u578b\u552f\u4e00\u6807\u8bc6', max_length=22, null=True, unique=True)), |
|
96 |
+ ('shot_type_name', models.CharField(blank=True, help_text='\u955c\u5934\u7c7b\u578b\u540d\u79f0', max_length=255, null=True, verbose_name='shot_type_name')), |
|
97 |
+ ('position', models.IntegerField(db_index=True, default=1, help_text='\u6392\u5e8f', verbose_name='position')), |
|
98 |
+ ], |
|
99 |
+ options={ |
|
100 |
+ 'verbose_name': '\u955c\u5934\u7c7b\u578b\u4fe1\u606f', |
|
101 |
+ 'verbose_name_plural': '\u955c\u5934\u7c7b\u578b\u4fe1\u606f', |
|
102 |
+ }, |
|
103 |
+ ), |
|
104 |
+ ] |
@@ -0,0 +1,211 @@ |
||
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, upload_file_path, upload_file_url, upload_path |
|
6 |
+from simditor.fields import RichTextField |
|
7 |
+from shortuuidfield import ShortUUIDField |
|
8 |
+ |
|
9 |
+from mch.models import ModelInfo |
|
10 |
+ |
|
11 |
+ |
|
12 |
+class GoodsInfo(BaseModelMixin): |
|
13 |
+ PHYSICAL = 0 |
|
14 |
+ VIRTUAL = 1 |
|
15 |
+ |
|
16 |
+ GOOD_TYPE_TUPLE = ( |
|
17 |
+ (PHYSICAL, u'实物'), |
|
18 |
+ (VIRTUAL, u'虚拟'), |
|
19 |
+ ) |
|
20 |
+ |
|
21 |
+ good_id = ShortUUIDField(_(u'good_id'), max_length=32, blank=True, null=True, help_text=u'商品唯一标识', db_index=True, unique=True) |
|
22 |
+ good_type = models.IntegerField(_(u'good_type'), choices=GOOD_TYPE_TUPLE, default=VIRTUAL, help_text=u'商品类型', db_index=True) |
|
23 |
+ |
|
24 |
+ title = models.CharField(_(u'title'), max_length=255, blank=True, null=True, help_text=u'商品名称') |
|
25 |
+ desc = RichTextField(_(u'desc'), blank=True, null=True, help_text=u'商品描述') |
|
26 |
+ |
|
27 |
+ image = models.ImageField(_(u'image'), upload_to=upload_path, blank=True, null=True, help_text=u'商品图片') |
|
28 |
+ |
|
29 |
+ is_slider = models.BooleanField(_(u'is_slider'), default=True, help_text=_(u'是否为轮播商品'), db_index=True) |
|
30 |
+ slider_image = models.ImageField(_(u'slider_image'), upload_to=upload_path, blank=True, null=True, help_text=u'商品轮播图片') |
|
31 |
+ |
|
32 |
+ integral = models.IntegerField(_(u'integral'), default=99999, help_text=u'兑换所需积分') |
|
33 |
+ fee = models.IntegerField(_(u'fee'), default=99999, help_text=u'兑换需额外支付金额,单位分') |
|
34 |
+ |
|
35 |
+ minlevel = models.IntegerField(_(u'minlevel'), default=0, help_text=u'兑换最低会员级别') |
|
36 |
+ |
|
37 |
+ position = models.IntegerField(_(u'position'), default=1, help_text=u'排序', db_index=True) |
|
38 |
+ |
|
39 |
+ class Meta: |
|
40 |
+ verbose_name = _(u'会员商品信息') |
|
41 |
+ verbose_name_plural = _(u'会员商品信息') |
|
42 |
+ |
|
43 |
+ def __unicode__(self): |
|
44 |
+ return unicode(self.pk) |
|
45 |
+ |
|
46 |
+ @property |
|
47 |
+ def image_path(self): |
|
48 |
+ return upload_file_path(self.image) |
|
49 |
+ |
|
50 |
+ @property |
|
51 |
+ def image_url(self): |
|
52 |
+ return upload_file_url(self.image) |
|
53 |
+ |
|
54 |
+ @property |
|
55 |
+ def slider_image_path(self): |
|
56 |
+ return upload_file_path(self.slider_image) |
|
57 |
+ |
|
58 |
+ @property |
|
59 |
+ def slider_image_url(self): |
|
60 |
+ return upload_file_url(self.slider_image) |
|
61 |
+ |
|
62 |
+ @property |
|
63 |
+ def data(self): |
|
64 |
+ return { |
|
65 |
+ 'good_id': self.good_id, |
|
66 |
+ 'good_type': self.good_type, |
|
67 |
+ 'title': self.title, |
|
68 |
+ 'desc': self.desc, |
|
69 |
+ 'image': self.image_url, |
|
70 |
+ 'slider_image': self.slider_image_url, |
|
71 |
+ 'integral': self.integral, |
|
72 |
+ 'fee': self.fee, |
|
73 |
+ 'minlevel': self.minlevel, |
|
74 |
+ 'able': True, |
|
75 |
+ } |
|
76 |
+ |
|
77 |
+ |
|
78 |
+class RightInfo(BaseModelMixin): |
|
79 |
+ right_id = ShortUUIDField(_(u'right_id'), max_length=32, blank=True, null=True, help_text=u'权益唯一标识', db_index=True, unique=True) |
|
80 |
+ |
|
81 |
+ icon = models.ImageField(_(u'icon'), upload_to=upload_path, blank=True, null=True, help_text=u'权益图标') |
|
82 |
+ title = models.CharField(_(u'title'), max_length=255, blank=True, null=True, help_text=u'权益名称') |
|
83 |
+ subtitle = models.CharField(_(u'subtitle'), max_length=255, blank=True, null=True, help_text=u'权益二级名称') |
|
84 |
+ detail = RichTextField(_(u'detail'), blank=True, null=True, help_text=u'权益详情') |
|
85 |
+ |
|
86 |
+ minlevel = models.IntegerField(_(u'minlevel'), default=0, help_text=u'权益最低会员级别') |
|
87 |
+ |
|
88 |
+ position = models.IntegerField(_(u'position'), default=1, help_text=u'排序', db_index=True) |
|
89 |
+ |
|
90 |
+ class Meta: |
|
91 |
+ verbose_name = _(u'会员权益信息') |
|
92 |
+ verbose_name_plural = _(u'会员权益信息') |
|
93 |
+ |
|
94 |
+ def __unicode__(self): |
|
95 |
+ return unicode(self.pk) |
|
96 |
+ |
|
97 |
+ @property |
|
98 |
+ def icon_path(self): |
|
99 |
+ return upload_file_path(self.icon) |
|
100 |
+ |
|
101 |
+ @property |
|
102 |
+ def icon_url(self): |
|
103 |
+ return upload_file_url(self.icon) |
|
104 |
+ |
|
105 |
+ @property |
|
106 |
+ def data(self): |
|
107 |
+ return { |
|
108 |
+ 'right_id': self.right_id, |
|
109 |
+ 'icon': self.icon_url, |
|
110 |
+ 'title': self.title, |
|
111 |
+ 'subtitle': self.subtitle, |
|
112 |
+ 'detail': self.detail, |
|
113 |
+ 'minlevel': self.minlevel, |
|
114 |
+ "able": True, |
|
115 |
+ "left_num": 3, |
|
116 |
+ "left_tip": 3, |
|
117 |
+ } |
|
118 |
+ |
|
119 |
+ |
|
120 |
+class ShotTypeInfo(BaseModelMixin): |
|
121 |
+ shot_type_id = ShortUUIDField(_(u'shot_type_id'), max_length=32, blank=True, null=True, help_text=u'镜头类型唯一标识', db_index=True, unique=True) |
|
122 |
+ shot_type_name = models.CharField(_(u'shot_type_name'), max_length=255, blank=True, null=True, help_text=u'镜头类型名称') |
|
123 |
+ |
|
124 |
+ position = models.IntegerField(_(u'position'), default=1, help_text=u'排序', db_index=True) |
|
125 |
+ |
|
126 |
+ class Meta: |
|
127 |
+ verbose_name = _(u'镜头类型信息') |
|
128 |
+ verbose_name_plural = _(u'镜头类型信息') |
|
129 |
+ |
|
130 |
+ def __unicode__(self): |
|
131 |
+ return unicode(self.pk) |
|
132 |
+ |
|
133 |
+ @property |
|
134 |
+ def shots(self): |
|
135 |
+ models = ModelInfo.objects.filter(shot_type_id=self.shot_type_id, status=True) |
|
136 |
+ return [model.shot_data for model in models] |
|
137 |
+ |
|
138 |
+ @property |
|
139 |
+ def data(self): |
|
140 |
+ return { |
|
141 |
+ 'type_id': self.shot_type_id, |
|
142 |
+ 'type_name': self.shot_type_name, |
|
143 |
+ 'shots': self.shots, |
|
144 |
+ } |
|
145 |
+ |
|
146 |
+ |
|
147 |
+class MemberActivityInfo(BaseModelMixin): |
|
148 |
+ title = models.CharField(_(u'title'), max_length=255, blank=True, null=True, help_text=u'活动名称') |
|
149 |
+ subtitle = models.CharField(_(u'subtitle'), max_length=255, blank=True, null=True, help_text=u'活动二级名称') |
|
150 |
+ |
|
151 |
+ date = models.DateField(_(u'date'), blank=True, null=True, help_text=u'活动时间') |
|
152 |
+ location = models.CharField(_(u'location'), max_length=255, blank=True, null=True, help_text=u'活动地点') |
|
153 |
+ |
|
154 |
+ image = models.ImageField(_(u'image'), upload_to=upload_path, blank=True, null=True, help_text=u'活动内容图片') |
|
155 |
+ |
|
156 |
+ cover = models.ImageField(_(u'cover'), upload_to=upload_path, blank=True, null=True, help_text=u'活动列表图片') |
|
157 |
+ |
|
158 |
+ is_slider = models.BooleanField(_(u'is_slider'), default=True, help_text=_(u'是否为轮播活动'), db_index=True) |
|
159 |
+ slider_image = models.ImageField(_(u'slider_image'), upload_to=upload_path, blank=True, null=True, help_text=u'活动轮播图片') |
|
160 |
+ |
|
161 |
+ content_rich_text = RichTextField(_(u'content_rich_text'), blank=True, null=True, help_text=u'活动描述') |
|
162 |
+ |
|
163 |
+ share_img_link = models.CharField(_(u'share_img_link'), max_length=255, blank=True, null=True, help_text=u'活动图片分享') |
|
164 |
+ share_h5_link = models.CharField(_(u'share_h5_link'), max_length=255, blank=True, null=True, help_text=u'活动H5分享') |
|
165 |
+ |
|
166 |
+ position = models.IntegerField(_(u'position'), default=1, help_text=u'排序', db_index=True) |
|
167 |
+ |
|
168 |
+ class Meta: |
|
169 |
+ verbose_name = _(u'会员活动信息') |
|
170 |
+ verbose_name_plural = _(u'会员活动信息') |
|
171 |
+ |
|
172 |
+ def __unicode__(self): |
|
173 |
+ return unicode(self.pk) |
|
174 |
+ |
|
175 |
+ @property |
|
176 |
+ def image_path(self): |
|
177 |
+ return upload_file_path(self.image) |
|
178 |
+ |
|
179 |
+ @property |
|
180 |
+ def image_url(self): |
|
181 |
+ return upload_file_url(self.image) |
|
182 |
+ |
|
183 |
+ @property |
|
184 |
+ def cover_path(self): |
|
185 |
+ return upload_file_path(self.cover) |
|
186 |
+ |
|
187 |
+ @property |
|
188 |
+ def cover_url(self): |
|
189 |
+ return upload_file_url(self.cover) |
|
190 |
+ |
|
191 |
+ @property |
|
192 |
+ def slider_image_path(self): |
|
193 |
+ return upload_file_path(self.slider_image) |
|
194 |
+ |
|
195 |
+ @property |
|
196 |
+ def slider_image_url(self): |
|
197 |
+ return upload_file_url(self.slider_image) |
|
198 |
+ |
|
199 |
+ @property |
|
200 |
+ def data(self): |
|
201 |
+ return { |
|
202 |
+ 'id': self.pk, |
|
203 |
+ 'title': self.title, |
|
204 |
+ 'subtitle': self.subtitle, |
|
205 |
+ 'date': self.date, |
|
206 |
+ 'location': self.location, |
|
207 |
+ 'cover_url': self.cover_url, |
|
208 |
+ 'content_rich_text': self.content_rich_text, |
|
209 |
+ 'state': 0, |
|
210 |
+ 'is_signed': 0, |
|
211 |
+ } |
@@ -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. |
@@ -2,11 +2,11 @@ |
||
2 | 2 |
|
3 | 3 |
from __future__ import division |
4 | 4 |
|
5 |
+import xlrd |
|
5 | 6 |
from django.conf import settings |
6 | 7 |
from pysnippets.strsnippets import strip |
7 | 8 |
from TimeConvert import TimeConvert as tc |
8 | 9 |
|
9 |
-import xlrd |
|
10 | 10 |
from mch.models import BrandInfo, ConsumeInfoSubmitLogInfo, DistributorInfo, ModelInfo |
11 | 11 |
from statistic.models import (ConsumeDistributorSaleStatisticInfo, ConsumeModelSaleStatisticInfo, |
12 | 12 |
ConsumeProvinceSaleStatisticInfo, ConsumeSaleStatisticInfo, ConsumeUserStatisticInfo, |
@@ -1,15 +1,15 @@ |
||
1 | 1 |
CodeConvert==2.0.5 |
2 |
-MySQL-python==1.2.5 |
|
3 | 2 |
Pillow==5.0.0 |
4 | 3 |
StatusCode==1.0.0 |
5 | 4 |
TimeConvert==1.5.0 |
6 |
-furl==2.0.0 |
|
5 |
+furl==2.1.0 |
|
7 | 6 |
isoweek==1.3.3 |
8 | 7 |
jsonfield==2.0.2 |
9 | 8 |
mock==2.0.0 |
10 | 9 |
monetary==1.0.3 |
11 |
-pysnippets==1.0.8 |
|
12 |
-qiniu==7.2.2 |
|
10 |
+mysqlclient==1.4.5 |
|
11 |
+pysnippets==1.1.2 |
|
12 |
+qiniu==7.2.6 |
|
13 | 13 |
requests==2.21.0 |
14 | 14 |
rlog==0.3 |
15 | 15 |
rsa==3.4.2 |
@@ -1,20 +1,20 @@ |
||
1 |
-Django==1.11.25 |
|
1 |
+Django==1.11.26 |
|
2 | 2 |
django-admin==2.0.0 |
3 |
-django-cors-headers==2.4.0 |
|
3 |
+django-cors-headers==3.0.2 |
|
4 | 4 |
django-curtail-uuid==1.0.4 |
5 |
-django-detect==1.0.8 |
|
5 |
+django-detect==1.0.16 |
|
6 | 6 |
django-file-md5==1.0.3 |
7 | 7 |
django-file-upload==1.1.1 |
8 | 8 |
django-ip==1.0.2 |
9 |
-django-json-render==1.0.2 |
|
9 |
+django-json-render==1.0.3 |
|
10 | 10 |
django-json-response==1.1.5 |
11 | 11 |
django-logit==1.1.3 |
12 | 12 |
django-mobi==0.1.7 |
13 | 13 |
django-models-ext==1.1.9 |
14 | 14 |
django-multidomain==1.1.4 |
15 | 15 |
django-paginator2==1.1.3 |
16 |
-django-query==1.0.3 |
|
17 |
-django-redis-connector==1.0.1 |
|
16 |
+django-query==1.0.6 |
|
17 |
+django-redis-connector==1.0.3 |
|
18 | 18 |
django-response==1.1.1 |
19 | 19 |
django-rlog==1.0.7 |
20 | 20 |
django-shortuuidfield==0.1.3 |
@@ -4,7 +4,7 @@ pywe-jssdk==1.1.0 |
||
4 | 4 |
pywe-membercard==1.0.1 |
5 | 5 |
pywe-miniapp==1.1.5 |
6 | 6 |
pywe-oauth==1.0.7 |
7 |
-pywe-pay==1.0.12 |
|
7 |
+pywe-pay==1.0.13 |
|
8 | 8 |
pywe-pay-notify==1.0.4 |
9 | 9 |
pywe-response==1.0.1 |
10 | 10 |
pywe-sign==1.1.0 |
@@ -1,3 +1,3 @@ |
||
1 |
-hiredis==1.0.0 |
|
1 |
+hiredis==1.0.1 |
|
2 | 2 |
redis==2.10.6 |
3 | 3 |
redis-extensions==1.2.5 |
@@ -0,0 +1,36 @@ |
||
1 |
+# -- coding: utf-8 -- |
|
2 |
+"""simditor fields.""" |
|
3 |
+from django import forms |
|
4 |
+from django.db import models |
|
5 |
+ |
|
6 |
+from .widgets import SimditorWidget |
|
7 |
+ |
|
8 |
+ |
|
9 |
+class RichTextFormField(forms.fields.CharField): |
|
10 |
+ """RichTextFormField.""" |
|
11 |
+ |
|
12 |
+ def __init__(self, *args, **kwargs): |
|
13 |
+ kwargs.update( |
|
14 |
+ { |
|
15 |
+ 'widget': SimditorWidget() |
|
16 |
+ } |
|
17 |
+ ) |
|
18 |
+ super(RichTextFormField, self).__init__(*args, **kwargs) |
|
19 |
+ |
|
20 |
+ |
|
21 |
+class RichTextField(models.TextField): |
|
22 |
+ """RichTextField.""" |
|
23 |
+ |
|
24 |
+ def __init__(self, *args, **kwargs): |
|
25 |
+ super(RichTextField, self).__init__(*args, **kwargs) |
|
26 |
+ |
|
27 |
+ def formfield(self, **kwargs): |
|
28 |
+ defaults = { |
|
29 |
+ 'form_class': self._get_form_class() |
|
30 |
+ } |
|
31 |
+ defaults.update(kwargs) |
|
32 |
+ return super(RichTextField, self).formfield(**defaults) |
|
33 |
+ |
|
34 |
+ @staticmethod |
|
35 |
+ def _get_form_class(): |
|
36 |
+ return RichTextFormField |
@@ -0,0 +1,11 @@ |
||
1 |
+# -- coding: utf-8 -- |
|
2 |
+"""simditor image pillow_backend.""" |
|
3 |
+from __future__ import absolute_import |
|
4 |
+ |
|
5 |
+from simditor import utils |
|
6 |
+ |
|
7 |
+ |
|
8 |
+def image_verify(file_object): |
|
9 |
+ """image_verify.""" |
|
10 |
+ if not utils.is_valid_image_extension(file_object.name): |
|
11 |
+ raise utils.NotAnImageException |
@@ -0,0 +1,28 @@ |
||
1 |
+# -- coding: utf-8 -- |
|
2 |
+"""simditor image pillow_backend.""" |
|
3 |
+from __future__ import absolute_import |
|
4 |
+ |
|
5 |
+import os |
|
6 |
+from io import BytesIO |
|
7 |
+ |
|
8 |
+from django.core.files.storage import default_storage |
|
9 |
+from django.core.files.uploadedfile import InMemoryUploadedFile |
|
10 |
+ |
|
11 |
+from simditor import utils |
|
12 |
+ |
|
13 |
+ |
|
14 |
+try: |
|
15 |
+ from PIL import Image, ImageOps |
|
16 |
+except ImportError: |
|
17 |
+ import Image |
|
18 |
+ import ImageOps |
|
19 |
+ |
|
20 |
+ |
|
21 |
+THUMBNAIL_SIZE = (75, 75) |
|
22 |
+ |
|
23 |
+ |
|
24 |
+def image_verify(f): |
|
25 |
+ try: |
|
26 |
+ Image.open(f).verify() |
|
27 |
+ except IOError: |
|
28 |
+ raise utils.NotAnImageException |
@@ -0,0 +1,16 @@ |
||
1 |
+# -- coding: utf-8 -- |
|
2 |
+"""simditor image_processing.""" |
|
3 |
+from __future__ import absolute_import |
|
4 |
+ |
|
5 |
+from django.conf import settings |
|
6 |
+ |
|
7 |
+ |
|
8 |
+def get_backend(): |
|
9 |
+ """Get backend.""" |
|
10 |
+ backend = getattr(settings, 'SIMDITOR_IMAGE_BACKEND', None) |
|
11 |
+ |
|
12 |
+ if backend == 'pillow': |
|
13 |
+ from simditor.image import pillow_backend as backend |
|
14 |
+ else: |
|
15 |
+ from simditor.image import dummy_backend as backend |
|
16 |
+ return backend |
@@ -0,0 +1,11 @@ |
||
1 |
+<?xml version="1.0" standalone="no"?> |
|
2 |
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > |
|
3 |
+<svg xmlns="http://www.w3.org/2000/svg"> |
|
4 |
+<metadata>Generated by IcoMoon</metadata> |
|
5 |
+<defs> |
|
6 |
+<font id="icomoon" horiz-adv-x="512"> |
|
7 |
+<font-face units-per-em="512" ascent="480" descent="-32" /> |
|
8 |
+<missing-glyph horiz-adv-x="512" /> |
|
9 |
+<glyph unicode=" " d="" horiz-adv-x="256" /> |
|
10 |
+<glyph unicode="" d="M438.624 86.624l-73.376 73.376-45.248-45.248 73.376-73.376-73.376-73.376h192v192zM192 480h-192v-192l73.376 73.376 72.688-72.624 45.248 45.248-72.688 72.624zM192 114.752l-45.248 45.248-73.376-73.376-73.376 73.376v-192h192l-73.376 73.376zM512 480h-192l73.376-73.376-72.688-72.624 45.248-45.248 72.688 72.624 73.376-73.376z" /> |
|
11 |
+</font></defs></svg> |
@@ -0,0 +1,82 @@ |
||
1 |
+{ |
|
2 |
+ "IcoMoonType": "selection", |
|
3 |
+ "icons": [ |
|
4 |
+ { |
|
5 |
+ "icon": { |
|
6 |
+ "paths": [ |
|
7 |
+ "M877.248 786.752l-146.752-146.752-90.496 90.496 146.752 146.752-146.752 146.752h384v-384zM384 0h-384v384l146.752-146.752 145.376 145.248 90.496-90.496-145.376-145.248zM384 730.496l-90.496-90.496-146.752 146.752-146.752-146.752v384h384l-146.752-146.752zM1024 0h-384l146.752 146.752-145.376 145.248 90.496 90.496 145.376-145.248 146.752 146.752z" |
|
8 |
+ ], |
|
9 |
+ "tags": [ |
|
10 |
+ "fullscreen", |
|
11 |
+ "expand" |
|
12 |
+ ], |
|
13 |
+ "grid": 16, |
|
14 |
+ "attrs": [] |
|
15 |
+ }, |
|
16 |
+ "attrs": [], |
|
17 |
+ "properties": { |
|
18 |
+ "id": 99, |
|
19 |
+ "order": 2, |
|
20 |
+ "prevSize": 16, |
|
21 |
+ "code": 58880, |
|
22 |
+ "name": "fullscreen" |
|
23 |
+ }, |
|
24 |
+ "setIdx": 1, |
|
25 |
+ "setId": 6, |
|
26 |
+ "iconIdx": 99 |
|
27 |
+ } |
|
28 |
+ ], |
|
29 |
+ "height": 1024, |
|
30 |
+ "metadata": { |
|
31 |
+ "name": "icomoon" |
|
32 |
+ }, |
|
33 |
+ "preferences": { |
|
34 |
+ "fontPref": { |
|
35 |
+ "prefix": "icon-", |
|
36 |
+ "metadata": { |
|
37 |
+ "fontFamily": "icomoon", |
|
38 |
+ "majorVersion": 1, |
|
39 |
+ "minorVersion": 0 |
|
40 |
+ }, |
|
41 |
+ "showGlyphs": true, |
|
42 |
+ "metrics": { |
|
43 |
+ "emSize": 512, |
|
44 |
+ "baseline": 6.25, |
|
45 |
+ "whitespace": 50 |
|
46 |
+ }, |
|
47 |
+ "resetPoint": 58880, |
|
48 |
+ "showQuickUse": true, |
|
49 |
+ "quickUsageToken": false, |
|
50 |
+ "showMetrics": false, |
|
51 |
+ "showMetadata": false, |
|
52 |
+ "autoHost": true, |
|
53 |
+ "embed": false, |
|
54 |
+ "ie7": false, |
|
55 |
+ "showSelector": false, |
|
56 |
+ "showVersion": true |
|
57 |
+ }, |
|
58 |
+ "imagePref": { |
|
59 |
+ "color": 0, |
|
60 |
+ "height": 32, |
|
61 |
+ "columns": 16, |
|
62 |
+ "margin": 16, |
|
63 |
+ "png": false, |
|
64 |
+ "sprites": true, |
|
65 |
+ "prefix": "icon-" |
|
66 |
+ }, |
|
67 |
+ "historySize": 100, |
|
68 |
+ "showCodes": true, |
|
69 |
+ "gridSize": 16, |
|
70 |
+ "showLiga": false, |
|
71 |
+ "showGrid": true, |
|
72 |
+ "showGlyphs": true, |
|
73 |
+ "showQuickUse": true, |
|
74 |
+ "search": "", |
|
75 |
+ "quickUsageToken": { |
|
76 |
+ "UntitledProject1": "ZWEwOTk2NTRmNjMyOGQ1MzAwZWFiYmJlODViMWMzZDcjMiMxNDA3NzM0MTA2IyMj" |
|
77 |
+ }, |
|
78 |
+ "showQuickUse2": true, |
|
79 |
+ "showSVGs": true, |
|
80 |
+ "fontHostingName": false |
|
81 |
+ } |
|
82 |
+} |
@@ -0,0 +1 @@ |