@@ -4,7 +4,7 @@ from curtail_uuid import CurtailUUID  | 
            ||
| 4 | 4 | 
                from django.contrib import admin  | 
            
| 5 | 5 | 
                from django.contrib.auth.hashers import make_password  | 
            
| 6 | 6 | 
                 | 
            
| 7 | 
                -from account.models import LensmanInfo, LensmanLoginLogInfo, UserInfo, UserLoginLogInfo  | 
            |
| 7 | 
                +from account.models import LensmanIncomeExpensesInfo, LensmanInfo, LensmanLoginLogInfo, UserIncomeExpensesInfo, UserInfo, UserLoginLogInfo  | 
            |
| 8 | 8 | 
                 | 
            
| 9 | 9 | 
                 | 
            
| 10 | 10 | 
                class LensmanInfoAdmin(admin.ModelAdmin):  | 
            
                @@ -26,18 +26,30 @@ class LensmanLoginLogInfoAdmin(admin.ModelAdmin):  | 
            ||
| 26 | 26 | 
                     list_display = ('lensman_id', 'login_ip', 'login_result', 'status', 'created_at', 'updated_at')
               | 
            
| 27 | 27 | 
                 | 
            
| 28 | 28 | 
                 | 
            
| 29 | 
                +class LensmanIncomeExpensesInfoAdmin(admin.ModelAdmin):  | 
            |
| 30 | 
                +    list_display = ('lensman_id', 'photo_id', 'type', 'amount', 'balance', 'remark', 'status', 'created_at', 'updated_at')
               | 
            |
| 31 | 
                +    list_filter = ('type', 'status')
               | 
            |
| 32 | 
                +  | 
            |
| 33 | 
                +  | 
            |
| 29 | 34 | 
                class UserInfoAdmin(admin.ModelAdmin):  | 
            
| 30 | 35 | 
                     readonly_fields = ('user_id', )
               | 
            
| 31 | 
                -    list_display = ('user_id', 'username', 'wx_uid', 'name', 'sex', 'phone', 'location', 'user_status', 'status', 'created_at', 'updated_at')
               | 
            |
| 36 | 
                +    list_display = ('user_id', 'user_from', 'username', 'wx_uid', 'name', 'sex', 'phone', 'location', 'user_status', 'status', 'created_at', 'updated_at')
               | 
            |
| 32 | 37 | 
                     search_fields = ('name', 'phone', 'location')
               | 
            
| 33 | 
                -    list_filter = ('sex', 'status', 'user_status')
               | 
            |
| 38 | 
                +    list_filter = ('user_from', 'sex', 'user_status', 'status')
               | 
            |
| 34 | 39 | 
                 | 
            
| 35 | 40 | 
                 | 
            
| 36 | 41 | 
                class UserLoginLogInfoAdmin(admin.ModelAdmin):  | 
            
| 37 | 42 | 
                     list_display = ('user_id', 'login_ip', 'login_result', 'status', 'created_at', 'updated_at')
               | 
            
| 38 | 43 | 
                 | 
            
| 39 | 44 | 
                 | 
            
| 45 | 
                +class UserIncomeExpensesInfoAdmin(admin.ModelAdmin):  | 
            |
| 46 | 
                +    list_display = ('user_id', 'photo_id', 'type', 'amount', 'balance', 'remark', 'status', 'created_at', 'updated_at')
               | 
            |
| 47 | 
                +    list_filter = ('type', 'status')
               | 
            |
| 48 | 
                +  | 
            |
| 49 | 
                +  | 
            |
| 40 | 50 | 
                admin.site.register(LensmanInfo, LensmanInfoAdmin)  | 
            
| 41 | 
                -admin.site.register(UserInfo, UserInfoAdmin)  | 
            |
| 42 | 51 | 
                admin.site.register(LensmanLoginLogInfo, LensmanLoginLogInfoAdmin)  | 
            
| 52 | 
                +admin.site.register(LensmanIncomeExpensesInfo, LensmanIncomeExpensesInfoAdmin)  | 
            |
| 53 | 
                +admin.site.register(UserInfo, UserInfoAdmin)  | 
            |
| 43 | 54 | 
                admin.site.register(UserLoginLogInfo, UserLoginLogInfoAdmin)  | 
            
| 55 | 
                +admin.site.register(UserIncomeExpensesInfo, UserIncomeExpensesInfoAdmin)  | 
            
                @@ -0,0 +1,72 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +from __future__ import unicode_literals  | 
            |
| 3 | 
                +  | 
            |
| 4 | 
                +from django.db import models, migrations  | 
            |
| 5 | 
                +  | 
            |
| 6 | 
                +  | 
            |
| 7 | 
                +class Migration(migrations.Migration):  | 
            |
| 8 | 
                +  | 
            |
| 9 | 
                + dependencies = [  | 
            |
| 10 | 
                +        ('account', '0008_userinfo_unionid'),
               | 
            |
| 11 | 
                + ]  | 
            |
| 12 | 
                +  | 
            |
| 13 | 
                + operations = [  | 
            |
| 14 | 
                + migrations.CreateModel(  | 
            |
| 15 | 
                + name='LensmanIncomeExpensesInfo',  | 
            |
| 16 | 
                + fields=[  | 
            |
| 17 | 
                +                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
               | 
            |
| 18 | 
                +                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', db_index=True, verbose_name='status')),
               | 
            |
| 19 | 
                +                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
               | 
            |
| 20 | 
                +                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
               | 
            |
| 21 | 
                +                ('lensman_id', models.CharField(max_length=255, blank=True, help_text='\u6444\u5f71\u5e08\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='lensman_id', db_index=True)),
               | 
            |
| 22 | 
                +                ('photo_id', models.CharField(max_length=255, blank=True, help_text='\u7167\u7247\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='photo_id', db_index=True)),
               | 
            |
| 23 | 
                +                ('type', models.IntegerField(default=0, help_text='\u6536\u652f\u7c7b\u522b', verbose_name='type', choices=[(0, '\u6536\u5165'), (1, '\u652f\u51fa')])),
               | 
            |
| 24 | 
                +                ('amount', models.IntegerField(default=0, help_text='\u4f59\u989d\u589e\u51cf\u6570\u91cf(\u5206)', verbose_name='amount')),
               | 
            |
| 25 | 
                +                ('balance', models.IntegerField(default=0, help_text='\u4f59\u989d\u589e\u51cf\u540e\u6570\u91cf(\u5206)', verbose_name='balance')),
               | 
            |
| 26 | 
                +                ('remark', models.CharField(help_text='\u5907\u6ce8', max_length=255, null=True, verbose_name='remark', blank=True)),
               | 
            |
| 27 | 
                + ],  | 
            |
| 28 | 
                +            options={
               | 
            |
| 29 | 
                + 'verbose_name': 'lensmanincomeexpensesinfo',  | 
            |
| 30 | 
                + 'verbose_name_plural': 'lensmanincomeexpensesinfo',  | 
            |
| 31 | 
                + },  | 
            |
| 32 | 
                + ),  | 
            |
| 33 | 
                + migrations.CreateModel(  | 
            |
| 34 | 
                + name='UserIncomeExpensesInfo',  | 
            |
| 35 | 
                + fields=[  | 
            |
| 36 | 
                +                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
               | 
            |
| 37 | 
                +                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', db_index=True, verbose_name='status')),
               | 
            |
| 38 | 
                +                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
               | 
            |
| 39 | 
                +                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
               | 
            |
| 40 | 
                +                ('user_id', models.CharField(max_length=255, blank=True, help_text='\u7528\u6237\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='user_id', db_index=True)),
               | 
            |
| 41 | 
                +                ('photo_id', models.CharField(max_length=255, blank=True, help_text='\u7167\u7247\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='photo_id', db_index=True)),
               | 
            |
| 42 | 
                +                ('type', models.IntegerField(default=0, help_text='\u6536\u652f\u7c7b\u522b', verbose_name='type', choices=[(0, '\u6536\u5165'), (1, '\u652f\u51fa')])),
               | 
            |
| 43 | 
                +                ('amount', models.IntegerField(default=0, help_text='\u4f59\u989d\u589e\u51cf\u6570\u91cf(\u5206)', verbose_name='amount')),
               | 
            |
| 44 | 
                +                ('balance', models.IntegerField(default=0, help_text='\u4f59\u989d\u589e\u51cf\u540e\u6570\u91cf(\u5206)', verbose_name='balance')),
               | 
            |
| 45 | 
                +                ('remark', models.CharField(help_text='\u5907\u6ce8', max_length=255, null=True, verbose_name='remark', blank=True)),
               | 
            |
| 46 | 
                + ],  | 
            |
| 47 | 
                +            options={
               | 
            |
| 48 | 
                + 'verbose_name': 'userincomeexpensesinfo',  | 
            |
| 49 | 
                + 'verbose_name_plural': 'userincomeexpensesinfo',  | 
            |
| 50 | 
                + },  | 
            |
| 51 | 
                + ),  | 
            |
| 52 | 
                + migrations.AddField(  | 
            |
| 53 | 
                + model_name='lensmaninfo',  | 
            |
| 54 | 
                + name='balance',  | 
            |
| 55 | 
                + field=models.IntegerField(default=0, help_text='\u6444\u5f71\u5e08\u4f59\u989d(\u5206)', verbose_name='balance'),  | 
            |
| 56 | 
                + ),  | 
            |
| 57 | 
                + migrations.AddField(  | 
            |
| 58 | 
                + model_name='userinfo',  | 
            |
| 59 | 
                + name='balance',  | 
            |
| 60 | 
                + field=models.IntegerField(default=0, help_text='\u7528\u6237\u4f59\u989d(\u5206)', verbose_name='balance'),  | 
            |
| 61 | 
                + ),  | 
            |
| 62 | 
                + migrations.AlterField(  | 
            |
| 63 | 
                + model_name='lensmaninfo',  | 
            |
| 64 | 
                + name='proportion',  | 
            |
| 65 | 
                + field=models.FloatField(default=1.0, help_text='\u6444\u5f71\u5e08\u5206\u6210\u6bd4\u4f8b(0.0 ~ 1.0)', verbose_name='proportion'),  | 
            |
| 66 | 
                + ),  | 
            |
| 67 | 
                + migrations.AlterField(  | 
            |
| 68 | 
                + model_name='userinfo',  | 
            |
| 69 | 
                + name='user_from',  | 
            |
| 70 | 
                + field=models.IntegerField(default=0, help_text='\u7528\u6237\u6765\u6e90', verbose_name='user_from', choices=[(0, 'APP \u521b\u5efa\u7528\u6237'), (1, '\u5fae\u4fe1\u6388\u6743\u7528\u6237'), (9, '\u6e38\u5ba2\u7528\u6237')]),  | 
            |
| 71 | 
                + ),  | 
            |
| 72 | 
                + ]  | 
            
                @@ -26,7 +26,9 @@ class LensmanInfo(CreateUpdateMixin):  | 
            ||
| 26 | 26 | 
                phone = models.CharField(_(u'phone'), max_length=255, blank=True, null=True, help_text=u'摄影师电话', db_index=True, unique=True)  | 
            
| 27 | 27 | 
                location = models.CharField(_(u'location'), max_length=255, blank=True, null=True, help_text=u'摄影师地址')  | 
            
| 28 | 28 | 
                 | 
            
| 29 | 
                - proportion = models.FloatField(_(u'proportion'), default=1.0, help_text=u'摄影师分成比例(0.0 ~ 1.0)')  | 
            |
| 29 | 
                + proportion = models.FloatField(_(u'proportion'), default=1.0, help_text=u'摄影师分成比例(0.0 ~ 1.0)')  | 
            |
| 30 | 
                +  | 
            |
| 31 | 
                + balance = models.IntegerField(_(u'balance'), default=0, help_text=u'摄影师余额(分)')  | 
            |
| 30 | 32 | 
                 | 
            
| 31 | 33 | 
                signup_ip = models.CharField(_(u'signup_ip'), max_length=255, blank=True, null=True, help_text=_(u'注册IP'))  | 
            
| 32 | 34 | 
                login_ip = models.CharField(_(u'login_ip'), max_length=255, blank=True, null=True, help_text=_(u'登录IP'))  | 
            
                @@ -63,13 +65,41 @@ class LensmanLoginLogInfo(CreateUpdateMixin):  | 
            ||
| 63 | 65 | 
                return unicode(self.pk)  | 
            
| 64 | 66 | 
                 | 
            
| 65 | 67 | 
                 | 
            
| 68 | 
                +class LensmanIncomeExpensesInfo(CreateUpdateMixin):  | 
            |
| 69 | 
                + INCOME = 0  | 
            |
| 70 | 
                + EXPENSE = 1  | 
            |
| 71 | 
                +  | 
            |
| 72 | 
                + TYPE = (  | 
            |
| 73 | 
                + (INCOME, u'收入'),  | 
            |
| 74 | 
                + (EXPENSE, u'支出'),  | 
            |
| 75 | 
                + )  | 
            |
| 76 | 
                +  | 
            |
| 77 | 
                + lensman_id = models.CharField(_(u'lensman_id'), max_length=255, blank=True, null=True, help_text=u'摄影师唯一标识', db_index=True)  | 
            |
| 78 | 
                + photo_id = models.CharField(_(u'photo_id'), max_length=255, blank=True, null=True, help_text=u'照片唯一标识', db_index=True)  | 
            |
| 79 | 
                +  | 
            |
| 80 | 
                + type = models.IntegerField(_(u'type'), choices=TYPE, default=INCOME, help_text=u'收支类别')  | 
            |
| 81 | 
                + amount = models.IntegerField(_(u'amount'), default=0, help_text=u'余额增减数量(分)')  | 
            |
| 82 | 
                + balance = models.IntegerField(_(u'balance'), default=0, help_text=u'余额增减后数量(分)')  | 
            |
| 83 | 
                +  | 
            |
| 84 | 
                + remark = models.CharField(_(u'remark'), max_length=255, blank=True, null=True, help_text=u'备注')  | 
            |
| 85 | 
                +  | 
            |
| 86 | 
                + class Meta:  | 
            |
| 87 | 
                + verbose_name = _(u'lensmanincomeexpensesinfo')  | 
            |
| 88 | 
                + verbose_name_plural = _(u'lensmanincomeexpensesinfo')  | 
            |
| 89 | 
                +  | 
            |
| 90 | 
                + def __unicode__(self):  | 
            |
| 91 | 
                + return unicode(self.pk)  | 
            |
| 92 | 
                +  | 
            |
| 93 | 
                +  | 
            |
| 66 | 94 | 
                class UserInfo(CreateUpdateMixin):  | 
            
| 67 | 95 | 
                APP_USER = 0  | 
            
| 68 | 96 | 
                WX_USER = 1  | 
            
| 97 | 
                + GUEST_USER = 9  | 
            |
| 69 | 98 | 
                 | 
            
| 70 | 99 | 
                USER_FROM = (  | 
            
| 71 | 100 | 
                (APP_USER, u'APP 创建用户'),  | 
            
| 72 | 101 | 
                (WX_USER, u'微信授权用户'),  | 
            
| 102 | 
                + (GUEST_USER, u'游客用户'),  | 
            |
| 73 | 103 | 
                )  | 
            
| 74 | 104 | 
                 | 
            
| 75 | 105 | 
                UNVERIFIED = 0  | 
            
                @@ -115,6 +145,8 @@ class UserInfo(CreateUpdateMixin):  | 
            ||
| 115 | 145 | 
                city = models.CharField(_(u'city'), max_length=255, blank=True, null=True, help_text=u'用户城市')  | 
            
| 116 | 146 | 
                location = models.CharField(_(u'location'), max_length=255, blank=True, null=True, help_text=u'用户地址')  | 
            
| 117 | 147 | 
                 | 
            
| 148 | 
                + balance = models.IntegerField(_(u'balance'), default=0, help_text=u'用户余额(分)')  | 
            |
| 149 | 
                +  | 
            |
| 118 | 150 | 
                user_status = models.IntegerField(_(u'user_status'), choices=USER_STATUS, default=UNVERIFIED)  | 
            
| 119 | 151 | 
                 | 
            
| 120 | 152 | 
                assign_ip = models.CharField(_(u'assign_ip'), max_length=255, blank=True, null=True, help_text=_(u'分配IP'))  | 
            
                @@ -170,3 +202,29 @@ class UserLoginLogInfo(CreateUpdateMixin):  | 
            ||
| 170 | 202 | 
                 | 
            
| 171 | 203 | 
                def __unicode__(self):  | 
            
| 172 | 204 | 
                return unicode(self.pk)  | 
            
| 205 | 
                +  | 
            |
| 206 | 
                +  | 
            |
| 207 | 
                +class UserIncomeExpensesInfo(CreateUpdateMixin):  | 
            |
| 208 | 
                + INCOME = 0  | 
            |
| 209 | 
                + EXPENSE = 1  | 
            |
| 210 | 
                +  | 
            |
| 211 | 
                + TYPE = (  | 
            |
| 212 | 
                + (INCOME, u'收入'),  | 
            |
| 213 | 
                + (EXPENSE, u'支出'),  | 
            |
| 214 | 
                + )  | 
            |
| 215 | 
                +  | 
            |
| 216 | 
                + user_id = models.CharField(_(u'user_id'), max_length=255, blank=True, null=True, help_text=u'用户唯一标识', db_index=True)  | 
            |
| 217 | 
                + photo_id = models.CharField(_(u'photo_id'), max_length=255, blank=True, null=True, help_text=u'照片唯一标识', db_index=True)  | 
            |
| 218 | 
                +  | 
            |
| 219 | 
                + type = models.IntegerField(_(u'type'), choices=TYPE, default=INCOME, help_text=u'收支类别')  | 
            |
| 220 | 
                + amount = models.IntegerField(_(u'amount'), default=0, help_text=u'余额增减数量(分)')  | 
            |
| 221 | 
                + balance = models.IntegerField(_(u'balance'), default=0, help_text=u'余额增减后数量(分)')  | 
            |
| 222 | 
                +  | 
            |
| 223 | 
                + remark = models.CharField(_(u'remark'), max_length=255, blank=True, null=True, help_text=u'备注')  | 
            |
| 224 | 
                +  | 
            |
| 225 | 
                + class Meta:  | 
            |
| 226 | 
                + verbose_name = _(u'userincomeexpensesinfo')  | 
            |
| 227 | 
                + verbose_name_plural = _(u'userincomeexpensesinfo')  | 
            |
| 228 | 
                +  | 
            |
| 229 | 
                + def __unicode__(self):  | 
            |
| 230 | 
                + return unicode(self.pk)  | 
            
                @@ -1,6 +1,7 @@  | 
            ||
| 1 | 1 | 
                # -*- coding: utf-8 -*-  | 
            
| 2 | 2 | 
                 | 
            
| 3 | 3 | 
                from curtail_uuid import CurtailUUID  | 
            
| 4 | 
                +from django.conf import settings  | 
            |
| 4 | 5 | 
                from django.contrib.auth.hashers import check_password, make_password  | 
            
| 5 | 6 | 
                from django.contrib.auth.models import Group, User  | 
            
| 6 | 7 | 
                from django.http import JsonResponse  | 
            
                @@ -207,6 +208,19 @@ def wx_authorize_api(request):  | 
            ||
| 207 | 208 | 
                })  | 
            
| 208 | 209 | 
                 | 
            
| 209 | 210 | 
                 | 
            
| 211 | 
                +def guest_login_api(request):  | 
            |
| 212 | 
                + try:  | 
            |
| 213 | 
                + user = UserInfo.objects.get(user_id=settings.GUEST_USER_ID)  | 
            |
| 214 | 
                + except UserInfo.DoesNotExist:  | 
            |
| 215 | 
                + return response(UserStatusCode.GUEST_NOT_FOUND)  | 
            |
| 216 | 
                +  | 
            |
| 217 | 
                +    return JsonResponse({
               | 
            |
| 218 | 
                + 'status': 200,  | 
            |
| 219 | 
                + 'message': u'Guest 登录成功',  | 
            |
| 220 | 
                + 'data': user.data,  | 
            |
| 221 | 
                + })  | 
            |
| 222 | 
                +  | 
            |
| 223 | 
                +  | 
            |
| 210 | 224 | 
                class UserViewSet(viewsets.ModelViewSet):  | 
            
| 211 | 225 | 
                """  | 
            
| 212 | 226 | 
                API endpoint that allows users to be viewed or edited.  | 
            
                @@ -18,6 +18,8 @@ urlpatterns = [  | 
            ||
| 18 | 18 | 
                url(r'^u/login$', account_views.user_login_api, name='user_login_api'), # 用户登录  | 
            
| 19 | 19 | 
                 | 
            
| 20 | 20 | 
                url(r'^u/wx/authorize$', account_views.wx_authorize_api, name='wx_authorize_api'), # 微信用户授权  | 
            
| 21 | 
                +  | 
            |
| 22 | 
                + url(r'^u/guest$', account_views.guest_login_api, name='guest_login_api'), # 游客登录  | 
            |
| 21 | 23 | 
                ]  | 
            
| 22 | 24 | 
                 | 
            
| 23 | 25 | 
                # 群组相关  | 
            
                @@ -225,6 +225,7 @@ WECHAT_GET_OAUTH2_ACCESS_TOKEN = 'https://api.weixin.qq.com/sns/oauth2/access_to  | 
            ||
| 225 | 225 | 
                 | 
            
| 226 | 226 | 
                WECHAT_GET_USERINFO = 'https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s'  | 
            
| 227 | 227 | 
                 | 
            
| 228 | 
                +# 微信支付设置  | 
            |
| 228 | 229 | 
                WXPAY_NOTIFY_SUCCESS = '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>'  | 
            
| 229 | 230 | 
                WXPAY_NOTIFY_FAIL = '<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[XML PARSE FAIL]]></return_msg></xml>'  | 
            
| 230 | 231 | 
                 | 
            
                @@ -250,6 +251,9 @@ PAI2_HOME_MAX_ROWS = 400 # 首页照片最大数量, PAI2_HOME_PER_PAGE * PAI2_  | 
            ||
| 250 | 251 | 
                # 群组设置  | 
            
| 251 | 252 | 
                GROUP_PER_PAGE = 20 # 群组每页数量  | 
            
| 252 | 253 | 
                 | 
            
| 254 | 
                +# 游客设置  | 
            |
| 255 | 
                +GUEST_USER_ID = 'guest'  | 
            |
| 256 | 
                +  | 
            |
| 253 | 257 | 
                # 价格设置  | 
            
| 254 | 258 | 
                LENSMAN_PHOTO_HAGGLE_MAX_TIMES = 3 # 摄影师照片最大砍价次数  | 
            
| 255 | 259 | 
                 | 
            
                @@ -26,6 +26,8 @@ class UserStatusCode(BaseStatusCode):  | 
            ||
| 26 | 26 | 
                USER_PASSWORD_ERROR = StatusCodeField(400102, u'User Password Error', description=u'用户密码错误')  | 
            
| 27 | 27 | 
                USERNAME_HAS_REGISTERED = StatusCodeField(400103, u'Username Has Registered', description=u'用户名已注册')  | 
            
| 28 | 28 | 
                 | 
            
| 29 | 
                + GUEST_NOT_FOUND = StatusCodeField(400111, u'Guest Not Found', description=u'游客不存在')  | 
            |
| 30 | 
                +  | 
            |
| 29 | 31 | 
                 | 
            
| 30 | 32 | 
                class PhotoStatusCode(BaseStatusCode):  | 
            
| 31 | 33 | 
                """ 照片相关错误码 4010xx """  |