From ee42d80d93a68e59f25e80787589c96cf6756660 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Fri, 19 Jun 2026 18:57:50 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=BA=86=20SDK=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86=20aggregate=20=E4=B8=8D=E8=83=BD?= =?UTF-8?q?=E4=BC=A0=E5=85=A5=20args=20=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- a_long_dianjing/settings.py | 2 +- backend/view.py | 2 +- config/views.py | 6 +- gvsdsdk/auth/elt_auth.py | 3 +- gvsdsdk/auth/managers.py | 2 +- gvsdsdk/auth/permissions.py | 3 +- gvsdsdk/management/commands/hash_passwords.py | 4 +- gvsdsdk/migrations/0001_initial.py | 35 +- ...002_position_roleposition_roleshop_shop.py | 90 ++++ gvsdsdk/models.py | 157 +----- migrate_to_gvsdsdk_user.py | 3 +- orders/tasks.py | 2 +- orders/views.py | 2 +- products/views.py | 2 +- rank/utils.py | 2 +- rank/views.py | 2 +- shop/models.py | 2 +- shop/views.py | 2 +- users/business_models.py | 171 ++++++ users/migrations/0001_initial.py | 507 ++++++++++-------- ...ofile_user_alter_userboss_user_and_more.py | 56 -- users/models.py | 24 +- users/paihang_views.py | 2 +- users/ranking_tasks.py | 2 +- users/tixian_shenhe_services.py | 2 +- users/views.py | 4 +- utils/chat_utils.py | 2 +- 27 files changed, 622 insertions(+), 469 deletions(-) create mode 100644 gvsdsdk/migrations/0002_position_roleposition_roleshop_shop.py create mode 100644 users/business_models.py delete mode 100644 users/migrations/0002_alter_adminprofile_user_alter_userboss_user_and_more.py diff --git a/a_long_dianjing/settings.py b/a_long_dianjing/settings.py index 0c21fed..2c94357 100644 --- a/a_long_dianjing/settings.py +++ b/a_long_dianjing/settings.py @@ -175,7 +175,7 @@ AUTHENTICATION_BACKENDS = [ 'django.contrib.auth.backends.ModelBackend', ] -AUTH_USER_MODEL = 'gvsdsdk.User' +AUTH_USER_MODEL = 'users.User' # ==================== DRF 配置 ==================== REST_FRAMEWORK = { diff --git a/backend/view.py b/backend/view.py index 1086eb3..514f536 100644 --- a/backend/view.py +++ b/backend/view.py @@ -61,7 +61,7 @@ from users.models import ( UserGuanshi, UserBoss, UserZuzhang, UserKefu, UserDashou, Xiugaijilu, UserShangjia, UserShenheguan ) -from gvsdsdk.models import User +from users.business_models import User ## orders from orders.models import ( diff --git a/config/views.py b/config/views.py index 8299cfe..b66e9f1 100644 --- a/config/views.py +++ b/config/views.py @@ -40,7 +40,7 @@ from users.models import ( AdminProfile, UserDashou, UserBoss, UserShangjia, UserGuanshi, UserZuzhang ) -from gvsdsdk.models import User +from users.business_models import User from orders.models import CommissionRate, Order, MerchantOrderExt from orders.notice_tasks import dingdan_guangbo @@ -2715,13 +2715,13 @@ class GuanZhuAListView(APIView): images = list(qs.values_list('ImageURL', flat=True)) # 获取最新更新时间(取所有记录的update_time最大值) - last_update = qs.aggregate(Max('update_time'))['update_time__max'] + last_update = qs.aggregate(update_time__max=Max('update_time'))['update_time__max'] last_update_str = last_update.strftime('%Y-%m-%d %H:%M:%S') if last_update else None # 原子性增加访问次数 # 先更新所有记录,再获取更新后的最大次数 qs.update(AccessCount=F('AccessCount') + 1) - visit_count = qs.aggregate(Max('AccessCount'))['AccessCount__max'] or 0 + visit_count = qs.aggregate(access_count__max=Max('AccessCount'))['access_count__max'] or 0 return Response({ 'code': 0, diff --git a/gvsdsdk/auth/elt_auth.py b/gvsdsdk/auth/elt_auth.py index 0492bda..6b83ae6 100644 --- a/gvsdsdk/auth/elt_auth.py +++ b/gvsdsdk/auth/elt_auth.py @@ -13,7 +13,8 @@ class ELTAuthentication: except (ValueError, AttributeError): return None - from gvsdsdk.models import User, EphemeralToken + from gvsdsdk.models import EphemeralToken + from gvsds.apps.core.models import User import datetime try: diff --git a/gvsdsdk/auth/managers.py b/gvsdsdk/auth/managers.py index 942c83f..1b49a57 100644 --- a/gvsdsdk/auth/managers.py +++ b/gvsdsdk/auth/managers.py @@ -87,7 +87,7 @@ class RoleManager: @staticmethod def GetUsersForRole(RoleUUID): """获取拥有指定角色的所有用户""" - from gvsdsdk.models import User + from gvsds.apps.core.models import User user_uuids = UserRole.objects.filter(RoleUUID=RoleUUID).values_list('UserUUID', flat=True) return User.objects.filter(UserUUID__in=user_uuids) diff --git a/gvsdsdk/auth/permissions.py b/gvsdsdk/auth/permissions.py index 2e6dc71..3d4c258 100644 --- a/gvsdsdk/auth/permissions.py +++ b/gvsdsdk/auth/permissions.py @@ -1,4 +1,5 @@ -from gvsdsdk.models import User, UserRole, Role, RolePermission, Permission, UserABAC +from gvsds.apps.core.models import User +from gvsdsdk.models import UserRole, Role, RolePermission, Permission, UserABAC from rest_framework.permissions import BasePermission diff --git a/gvsdsdk/management/commands/hash_passwords.py b/gvsdsdk/management/commands/hash_passwords.py index 30647c4..b6c1ba3 100644 --- a/gvsdsdk/management/commands/hash_passwords.py +++ b/gvsdsdk/management/commands/hash_passwords.py @@ -1,6 +1,8 @@ """将 User 表中明文密码迁移为 bcrypt 哈希""" from django.core.management.base import BaseCommand -from gvsdsdk.models import User +from django.contrib.auth import get_user_model + +User = get_user_model() class Command(BaseCommand): diff --git a/gvsdsdk/migrations/0001_initial.py b/gvsdsdk/migrations/0001_initial.py index 96c02e9..f24fe51 100644 --- a/gvsdsdk/migrations/0001_initial.py +++ b/gvsdsdk/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.27 on 2026-06-17 17:07 +# Generated by Django 4.2.27 on 2026-06-19 18:42 import datetime from django.db import migrations, models @@ -318,37 +318,4 @@ class Migration(migrations.Migration): 'managed': True, }, ), - migrations.CreateModel( - name='User', - fields=[ - ('UserUUID', gvsdsdk.models.UUIDField(binary_length=16, db_column='UserUUID', primary_key=True, serialize=False, verbose_name='用户UUID')), - ('UserName', models.CharField(db_column='UserName', max_length=256, unique=True, verbose_name='用户名')), - ('UserPassword', models.CharField(db_column='UserPassword', default='', max_length=60, verbose_name='密码')), - ('UserPositionStatus', models.SmallIntegerField(db_column='UserPositionStatus', default=0, verbose_name='职位状态')), - ('UserPersonalSignature', models.CharField(db_column='UserPersonalSignature', default='', max_length=1024, verbose_name='个人签名')), - ('UserEmail', models.CharField(db_column='UserEmail', default='', max_length=256, verbose_name='邮箱')), - ('UserEmailVerify', models.SmallIntegerField(db_column='UserEmailVerify', default=0, verbose_name='邮箱验证')), - ('UserAccountLicense', models.SmallIntegerField(db_column='UserAccountLicense', default=1, verbose_name='账户许可')), - ('UserGender', models.SmallIntegerField(db_column='UserGender', default=-1, verbose_name='性别')), - ('UserTele', models.CharField(blank=True, db_column='UserTele', max_length=16, null=True, verbose_name='电话')), - ('UserCreateTime', models.DateTimeField(db_column='UserCreateTime', default=datetime.datetime.utcnow, verbose_name='创建时间')), - ('UserLastLoginDate', models.DateTimeField(db_column='UserLastLoginDate', default=datetime.datetime.utcnow, verbose_name='最后登录')), - ('UserUID', models.CharField(blank=True, db_column='UserUID', max_length=7, null=True, unique=True, verbose_name='用户业务ID')), - ('OpenID', models.CharField(blank=True, db_column='OpenID', max_length=64, null=True, unique=True, verbose_name='微信OpenID')), - ('UnionID', models.CharField(blank=True, db_column='UnionID', max_length=64, null=True, verbose_name='微信UnionID')), - ('Avatar', models.CharField(db_column='Avatar', default='a_long/morentouxiang.jpg', max_length=500, verbose_name='头像')), - ('Phone', models.CharField(blank=True, db_column='Phone', max_length=11, null=True, verbose_name='手机号')), - ('PhoneVerified', models.BooleanField(db_column='PhoneVerified', default=False, verbose_name='手机号是否已认证')), - ('IP', models.CharField(blank=True, db_column='IP', max_length=50, null=True, verbose_name='来访用户IP')), - ('IsStaff', models.BooleanField(db_column='IsStaff', default=False, verbose_name='是否员工')), - ('IsSuperuser', models.BooleanField(db_column='IsSuperuser', default=False, verbose_name='是否超级用户')), - ], - options={ - 'verbose_name': '用户', - 'verbose_name_plural': '用户', - 'db_table': 'User', - 'managed': True, - 'indexes': [models.Index(fields=['UserUID'], name='User_UserUID_a656ea_idx'), models.Index(fields=['OpenID'], name='User_OpenID_2a920d_idx')], - }, - ), ] diff --git a/gvsdsdk/migrations/0002_position_roleposition_roleshop_shop.py b/gvsdsdk/migrations/0002_position_roleposition_roleshop_shop.py new file mode 100644 index 0000000..8251940 --- /dev/null +++ b/gvsdsdk/migrations/0002_position_roleposition_roleshop_shop.py @@ -0,0 +1,90 @@ +# Generated by Django 6.0.5 on 2026-06-13 12:29 + +import datetime +import gvsdsdk.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('gvsdsdk', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Position', + fields=[ + ('PositionUUID', gvsdsdk.models.UUIDField(binary_length=16, db_column='PositionUUID', primary_key=True, serialize=False)), + ('CompanyUUID', gvsdsdk.models.UUIDField(binary_length=16, db_column='CompanyUUID')), + ('PositionName', models.CharField(db_column='PositionName', max_length=128)), + ('PositionCode', models.CharField(db_column='PositionCode', default='', max_length=64)), + ('PositionLevel', models.SmallIntegerField(db_column='PositionLevel', default=0)), + ('PositionStatus', models.SmallIntegerField(db_column='PositionStatus', default=1)), + ('PositionDesc', models.CharField(db_column='PositionDesc', default='', max_length=512)), + ('CreateTime', models.DateTimeField(db_column='CreateTime', default=datetime.datetime.utcnow)), + ('UpdateTime', models.DateTimeField(db_column='UpdateTime', default=datetime.datetime.utcnow)), + ], + options={ + 'verbose_name': '职务', + 'verbose_name_plural': '职务', + 'db_table': 'Position', + 'managed': True, + }, + ), + migrations.CreateModel( + name='RolePosition', + fields=[ + ('RolePositionUUID', gvsdsdk.models.UUIDField(binary_length=16, db_column='RolePositionUUID', primary_key=True, serialize=False)), + ('RoleUUID', gvsdsdk.models.UUIDField(binary_length=16, db_column='RoleUUID')), + ('PositionUUID', gvsdsdk.models.UUIDField(binary_length=16, db_column='PositionUUID')), + ('IsMainPosition', models.SmallIntegerField(db_column='IsMainPosition', default=0)), + ('CreateTime', models.DateTimeField(db_column='CreateTime', default=datetime.datetime.utcnow)), + ], + options={ + 'verbose_name': '角色职务关联', + 'verbose_name_plural': '角色职务关联', + 'db_table': 'RolePosition', + 'managed': True, + }, + ), + migrations.CreateModel( + name='RoleShop', + fields=[ + ('RoleShopUUID', gvsdsdk.models.UUIDField(binary_length=16, db_column='RoleShopUUID', primary_key=True, serialize=False)), + ('RoleUUID', gvsdsdk.models.UUIDField(binary_length=16, db_column='RoleUUID')), + ('ShopUUID', gvsdsdk.models.UUIDField(binary_length=16, db_column='ShopUUID')), + ('IsMainShop', models.SmallIntegerField(db_column='IsMainShop', default=0)), + ('CreateTime', models.DateTimeField(db_column='CreateTime', default=datetime.datetime.utcnow)), + ], + options={ + 'verbose_name': '角色商铺关联', + 'verbose_name_plural': '角色商铺关联', + 'db_table': 'RoleShop', + 'managed': True, + }, + ), + migrations.CreateModel( + name='Shop', + fields=[ + ('ShopUUID', gvsdsdk.models.UUIDField(binary_length=16, db_column='ShopUUID', primary_key=True, serialize=False)), + ('CompanyUUID', gvsdsdk.models.UUIDField(binary_length=16, db_column='CompanyUUID')), + ('ShopName', models.CharField(db_column='ShopName', max_length=128)), + ('ShopCode', models.CharField(db_column='ShopCode', default='', max_length=64)), + ('ShopType', models.SmallIntegerField(db_column='ShopType', default=0)), + ('ShopStatus', models.SmallIntegerField(db_column='ShopStatus', default=1)), + ('ShopAddress', models.CharField(db_column='ShopAddress', default='', max_length=512)), + ('ShopContact', models.CharField(db_column='ShopContact', default='', max_length=128)), + ('ShopPhone', models.CharField(db_column='ShopPhone', default='', max_length=32)), + ('ShopDesc', models.CharField(db_column='ShopDesc', default='', max_length=512)), + ('CreateTime', models.DateTimeField(db_column='CreateTime', default=datetime.datetime.utcnow)), + ('UpdateTime', models.DateTimeField(db_column='UpdateTime', default=datetime.datetime.utcnow)), + ], + options={ + 'verbose_name': '商铺', + 'verbose_name_plural': '商铺', + 'db_table': 'Shop', + 'managed': True, + }, + ), + ] diff --git a/gvsdsdk/models.py b/gvsdsdk/models.py index 60bf5f5..20262f9 100644 --- a/gvsdsdk/models.py +++ b/gvsdsdk/models.py @@ -13,10 +13,10 @@ 4. 鉴权规则层:操作权限校验(角色汇总)+ 数据权限校验(组织属性) 使用方式(子服务器): - from gvsdsdk.models import User, Permission, Role, UserRole, RolePermission + from gvsdsdk.models import Permission, Role, UserRole, RolePermission - # 查询所有启用的用户 - users = User.objects.using('saas').filter(UserAccountLicense=1) + # 查询所有启用的用户(需在业务子类中定义具体 User 模型) + users = User.objects.filter(UserAccountLicense=1) # 或配置 DatabaseRouter 后直接使用 users = User.objects.filter(UserAccountLicense=1) @@ -27,6 +27,10 @@ 3. PascalCase:字段名、方法名遵循帕斯卡命名法 4. 兼容:db_table、db_column 与 SAAS 主库完全一致 5. 租户隔离:所有权限相关数据依附于独立租户空间,不同租户互相不可见 + +注意:User 为抽象基类,仅包含 SAAS 主库标准字段。 + 业务子类应继承 User 并在单独文件中添加业务字段和方法。 + 参见 gvsdsdk/business_models.py。 """ import uuid as _uuid @@ -172,7 +176,12 @@ class UserManager(BaseUserManager): # === 用户表 === class User(QModel): - """用户表——系统核心身份模型(映射 SAAS 主库 User 表)""" + """用户表——系统核心身份模型(抽象基类,映射 SAAS 主库 User 表标准字段) + + 本类为抽象基类,仅包含 SAAS 主库 User 表的标准字段和方法。 + 业务子类应继承本类,在单独文件中添加业务字段和方法。 + 参见 gvsdsdk/business_models.py。 + """ UserUUID = UUIDField(primary_key=True, db_column='UserUUID', verbose_name='用户UUID', default=_uuid.uuid4) UserName = models.CharField(max_length=256, unique=True, db_column='UserName', verbose_name='用户名') @@ -186,34 +195,13 @@ class User(QModel): UserTele = models.CharField(max_length=16, null=True, blank=True, db_column='UserTele', verbose_name='电话') UserCreateTime = models.DateTimeField(default=_datetime.datetime.utcnow, db_column='UserCreateTime', verbose_name='创建时间') UserLastLoginDate = models.DateTimeField(default=_datetime.datetime.utcnow, db_column='UserLastLoginDate', verbose_name='最后登录') - # === 本地业务字段(去远程化后新增) === - UserUID = models.CharField(max_length=7, unique=True, db_column='UserUID', verbose_name='用户业务ID', null=True, blank=True) - OpenID = models.CharField(max_length=64, unique=True, db_column='OpenID', verbose_name='微信OpenID', null=True, blank=True) - UnionID = models.CharField(max_length=64, db_column='UnionID', verbose_name='微信UnionID', null=True, blank=True) - Avatar = models.CharField(max_length=500, default='a_long/morentouxiang.jpg', db_column='Avatar', verbose_name='头像') - Phone = models.CharField(max_length=11, db_column='Phone', verbose_name='手机号', null=True, blank=True) - PhoneVerified = models.BooleanField(default=False, db_column='PhoneVerified', verbose_name='手机号是否已认证') - IP = models.CharField(max_length=50, db_column='IP', verbose_name='来访用户IP', null=True, blank=True) - IsStaff = models.BooleanField(default=False, db_column='IsStaff', verbose_name='是否员工') - IsSuperuser = models.BooleanField(default=False, db_column='IsSuperuser', verbose_name='是否超级用户') - - objects = UserManager() - - # Django auth 框架必需 + # Django auth 框架必需(由具体子类覆盖) USERNAME_FIELD = 'UserName' - REQUIRED_FIELDS = ['UserUID'] + REQUIRED_FIELDS = [] class Meta: - managed = True # 将由 QModelBase.__new__ 根据 GVSDSDK_MANAGE_TABLES 动态设置 - app_label = 'gvsdsdk' - db_table = 'User' - verbose_name = '用户' - verbose_name_plural = '用户' - indexes = [ - models.Index(fields=['UserUID']), - models.Index(fields=['OpenID']), - ] + abstract = True def __str__(self): return self.UserName @@ -341,115 +329,6 @@ class User(QModel): def check_password(self, raw_password): return self.CheckPassword(raw_password) - # ── 用户类型推断(通过 UserRole → Role 推断,带实例缓存)── - - @property - def UserType(self): - """用户类型 — 通过 UserRole 推断(带实例缓存)""" - if hasattr(self, '_cached_user_type'): - return self._cached_user_type - try: - role_uuids = UserRole.objects.filter( - UserUUID=self.UserUUID - ).values_list('RoleUUID', flat=True) - role_names = set( - Role.objects.filter(RoleUUID__in=role_uuids) - .values_list('RoleName', flat=True) - ) - # 优先级:管理员 > 客服 > 负责人 > 组长 > 审核官 > 商家 > 打手 - for rn in role_names: - if '管理员' in rn or 'admin' in rn.lower(): - self._cached_user_type = 'admin' - return 'admin' - for rn in role_names: - if '客服' in rn or 'kefu' in rn.lower(): - self._cached_user_type = 'kefu' - return 'kefu' - for rn in role_names: - if '负责人' in rn or '管事' in rn or 'guanshi' in rn.lower(): - self._cached_user_type = 'guanshi' - return 'guanshi' - for rn in role_names: - if '组长' in rn or 'zuzhang' in rn.lower(): - self._cached_user_type = 'zuzhang' - return 'zuzhang' - for rn in role_names: - if '审核' in rn or 'shenheguan' in rn.lower(): - self._cached_user_type = 'shenheguan' - return 'shenheguan' - for rn in role_names: - if '商家' in rn or 'shangjia' in rn.lower(): - self._cached_user_type = 'shop' - return 'shop' - for rn in role_names: - if '打手' in rn or 'dashou' in rn.lower(): - self._cached_user_type = 'dashou' - return 'dashou' - self._cached_user_type = 'normal' - return 'normal' - except Exception: - self._cached_user_type = 'normal' - return 'normal' - - # ── 收款信息(存于 UserSensitiveData)── - - @property - def PaymentQRCode(self): - """收款码图片(存于 UserSensitiveData.zhifu)""" - try: - return self.sensitive_data.zhifu - except Exception: - return '' - - @PaymentQRCode.setter - def PaymentQRCode(self, value): - try: - sd = self.sensitive_data - sd.zhifu = value - sd.save(update_fields=['zhifu']) - except Exception: - pass - - @property - def PaymentAccount(self): - """收款账号(存于 UserSensitiveData.skzhanghao)""" - try: - return self.sensitive_data.skzhanghao - except Exception: - return '' - - @PaymentAccount.setter - def PaymentAccount(self, value): - try: - sd = self.sensitive_data - sd.skzhanghao = value - sd.save(update_fields=['skzhanghao']) - except Exception: - pass - - # ── 关联扩展表快捷访问 ── - # DashouProfile / ShopProfile / GuanshiProfile / BossProfile / - # AdminProfile / KefuProfile / ZuzhangProfile / ShenheguanProfile - # 均由 OneToOneField related_name 直接提供反向关联访问 - - def HasRole(self, role_code): - """检查用户是否拥有指定角色(支持角色名或 UserType 值)""" - ROLE_CODE_MAP = { - 'admin': '管理员', 'kefu': '客服', 'guanshi': '负责人', - 'zuzhang': '组长', 'shenheguan': '审核官', 'shop': '商家', - 'dashou': '打手', 'normal': '消费者', - } - target = ROLE_CODE_MAP.get(role_code, role_code) - try: - role_uuids = UserRole.objects.filter( - UserUUID=self.UserUUID - ).values_list('RoleUUID', flat=True) - return Role.objects.filter( - RoleUUID__in=role_uuids, RoleName=target - ).exists() - except Exception: - return False - # === 用户头像表 === @@ -622,10 +501,12 @@ class Role(QModel): def GetUsers(self): """获取拥有该角色的用户列表""" + from django.apps import apps + UserModel = apps.get_model('gvsdsdk', 'User') user_uuids = UserRole.objects.filter( RoleUUID=self.RoleUUID ).values_list('UserUUID', flat=True) - return User.objects.filter(UserUUID__in=user_uuids) + return UserModel.objects.filter(UserUUID__in=user_uuids) # === 权限表 === diff --git a/migrate_to_gvsdsdk_user.py b/migrate_to_gvsdsdk_user.py index c9c9843..8b1db82 100644 --- a/migrate_to_gvsdsdk_user.py +++ b/migrate_to_gvsdsdk_user.py @@ -46,7 +46,8 @@ PERMISSION_MAP = { def run_migration(): - from gvsdsdk.models import User, Role, Permission, UserRole, RolePermission + from gvsdsdk.models import Role, Permission, UserRole, RolePermission + from users.business_models import User from users.models import ( UserMain, UserBoss, UserDashou, UserShangjia, UserGuanshi, UserZuzhang, UserShenheguan, AdminProfile, UserKefu, diff --git a/orders/tasks.py b/orders/tasks.py index 572decc..4424bbb 100644 --- a/orders/tasks.py +++ b/orders/tasks.py @@ -16,7 +16,7 @@ import logging # 导入模型 - 确保路径正确 from orders.models import Order from users.models import UserDashou, UserShangjia -from gvsdsdk.models import User +from users.business_models import User from utils.celery_utils import safe_decimal_operation, log_task_execution, rollback_on_failure from gvsdsdk.fluent import db, func, FQ diff --git a/orders/views.py b/orders/views.py index aadd03b..6ee8544 100644 --- a/orders/views.py +++ b/orders/views.py @@ -63,7 +63,7 @@ from orders.models import ( ) from products.models import Shangpin, ShangpinLeixing, Huiyuangoumai from users.models import UserDashou, UserShangjia, UserBoss -from gvsdsdk.models import User +from users.business_models import User from rank.models import DashouBiaoxian, Chenghao, DingdanBiaoqian, YonghuChenghao from config.models import ( Szjilu, ShangjiaLianjie diff --git a/products/views.py b/products/views.py index 6940e60..60d709a 100644 --- a/products/views.py +++ b/products/views.py @@ -48,7 +48,7 @@ from .models import ( from users.models import ( AdminProfile, UserDashou, UserGuanshi, UserZuzhang, UserShangjia ) -from gvsdsdk.models import User +from users.business_models import User from orders.models import CommissionRate from config.models import Szjilu, Gonggao, Lunbo diff --git a/rank/utils.py b/rank/utils.py index 27732db..aa8b93a 100644 --- a/rank/utils.py +++ b/rank/utils.py @@ -13,7 +13,7 @@ from .models import ( ) ## users应用 from users.models import UserShenheguan, UserDashou -from gvsdsdk.models import User +from users.business_models import User ## orders应用 from .models import YonghuChenghao # 日志对象 diff --git a/rank/views.py b/rank/views.py index 90802d9..bbae71e 100644 --- a/rank/views.py +++ b/rank/views.py @@ -12,7 +12,7 @@ from .models import ( KaoheguanBankuai, Bankuai, ShenheJilu, KaoheJiluFeiyong ) from users.models import UserShenheguan, UserDashou -from gvsdsdk.models import User +from users.business_models import User from products.models import ShangpinLeixing diff --git a/shop/models.py b/shop/models.py index 93fc4eb..647f674 100644 --- a/shop/models.py +++ b/shop/models.py @@ -148,7 +148,7 @@ class DianpuShouzhiMeiriTongji(QModel): class YonghuDianpuBangding(QModel): id = models.AutoField(primary_key=True, verbose_name='绑定自增ID') yonghu = models.ForeignKey( - 'gvsdsdk.User', + 'users.User', on_delete=models.CASCADE, db_column='UserUUID', db_index=True, diff --git a/shop/views.py b/shop/views.py index 4d041d6..31d26bd 100644 --- a/shop/views.py +++ b/shop/views.py @@ -43,7 +43,7 @@ from backend.utils import update_dashou_daily_by_action from .models import YonghuPingzheng, Dianpu, DianpuShouzhiMeiriTongji from users.models import UserDashou, UserShangjia, UserGuanshi, UserZuzhang -from gvsdsdk.models import User +from users.business_models import User from shop.models import YonghuDianpuBangding, ShangpinLeixingDianpu, DianpuShangpinShenheShezhi diff --git a/users/business_models.py b/users/business_models.py new file mode 100644 index 0000000..37cbbc1 --- /dev/null +++ b/users/business_models.py @@ -0,0 +1,171 @@ +"""业务用户模型——继承 SDK 抽象基类,添加本服务业务字段和方法 + +本文件位于 users app(业务层),不属于 gvsdsdk SDK 包。 +User 类继承自 gvsdsdk.models.User(抽象基类),添加业务字段和方法。 + +业务字段: + - UserUID:用户业务ID(7位) + - OpenID / UnionID:微信认证字段 + - Avatar:头像路径 + - Phone / PhoneVerified:手机号及认证状态 + - IP:来访用户IP + - IsStaff / IsSuperuser:Django auth 框架必需 + +业务方法: + - UserType:通过 UserRole 推断用户类型(admin/kefu/guanshi/...) + - PaymentQRCode / PaymentAccount:收款信息(存于 UserSensitiveData) + - HasRole:检查用户是否拥有指定角色 +""" + +import datetime as _datetime +from django.db import models +from gvsdsdk.models import User as _UserBase, UserManager +from gvsdsdk.models import UserRole, Role + + +class User(_UserBase): + """业务用户表——继承 SDK 抽象 User,添加本服务业务字段和方法 + + 映射与 SDK 相同的 User 表(db_table='User'),但额外包含: + - 微信认证字段(OpenID, UnionID) + - 业务标识字段(UserUID, Avatar, Phone, IP) + - Django auth 扩展字段(IsStaff, IsSuperuser) + - 业务方法(UserType, PaymentQRCode, PaymentAccount, HasRole) + """ + + # === 本地业务字段 === + UserUID = models.CharField(max_length=7, unique=True, db_column='UserUID', verbose_name='用户业务ID', null=True, blank=True) + OpenID = models.CharField(max_length=64, unique=True, db_column='OpenID', verbose_name='微信OpenID', null=True, blank=True) + UnionID = models.CharField(max_length=64, db_column='UnionID', verbose_name='微信UnionID', null=True, blank=True) + Avatar = models.CharField(max_length=500, default='a_long/morentouxiang.jpg', db_column='Avatar', verbose_name='头像') + Phone = models.CharField(max_length=11, db_column='Phone', verbose_name='手机号', null=True, blank=True) + PhoneVerified = models.BooleanField(default=False, db_column='PhoneVerified', verbose_name='手机号是否已认证') + IP = models.CharField(max_length=50, db_column='IP', verbose_name='来访用户IP', null=True, blank=True) + IsStaff = models.BooleanField(default=False, db_column='IsStaff', verbose_name='是否员工') + IsSuperuser = models.BooleanField(default=False, db_column='IsSuperuser', verbose_name='是否超级用户') + + objects = UserManager() + + # Django auth 框架必需 + USERNAME_FIELD = 'UserName' + REQUIRED_FIELDS = ['UserUID'] + + class Meta: + managed = True + app_label = 'users' + db_table = 'User' + verbose_name = '用户' + verbose_name_plural = '用户' + indexes = [ + models.Index(fields=['UserUID']), + models.Index(fields=['OpenID']), + ] + + # ── 用户类型推断(通过 UserRole → Role 推断,带实例缓存)── + + @property + def UserType(self): + """用户类型 — 通过 UserRole 推断(带实例缓存)""" + if hasattr(self, '_cached_user_type'): + return self._cached_user_type + try: + role_uuids = UserRole.objects.filter( + UserUUID=self.UserUUID + ).values_list('RoleUUID', flat=True) + role_names = set( + Role.objects.filter(RoleUUID__in=role_uuids) + .values_list('RoleName', flat=True) + ) + # 优先级:管理员 > 客服 > 负责人 > 组长 > 审核官 > 商家 > 打手 + for rn in role_names: + if '管理员' in rn or 'admin' in rn.lower(): + self._cached_user_type = 'admin' + return 'admin' + for rn in role_names: + if '客服' in rn or 'kefu' in rn.lower(): + self._cached_user_type = 'kefu' + return 'kefu' + for rn in role_names: + if '负责人' in rn or '管事' in rn or 'guanshi' in rn.lower(): + self._cached_user_type = 'guanshi' + return 'guanshi' + for rn in role_names: + if '组长' in rn or 'zuzhang' in rn.lower(): + self._cached_user_type = 'zuzhang' + return 'zuzhang' + for rn in role_names: + if '审核' in rn or 'shenheguan' in rn.lower(): + self._cached_user_type = 'shenheguan' + return 'shenheguan' + for rn in role_names: + if '商家' in rn or 'shangjia' in rn.lower(): + self._cached_user_type = 'shop' + return 'shop' + for rn in role_names: + if '打手' in rn or 'dashou' in rn.lower(): + self._cached_user_type = 'dashou' + return 'dashou' + self._cached_user_type = 'normal' + return 'normal' + except Exception: + self._cached_user_type = 'normal' + return 'normal' + + # ── 收款信息(存于 UserSensitiveData)── + + @property + def PaymentQRCode(self): + """收款码图片(存于 UserSensitiveData.zhifu)""" + try: + return self.sensitive_data.zhifu + except Exception: + return '' + + @PaymentQRCode.setter + def PaymentQRCode(self, value): + try: + sd = self.sensitive_data + sd.zhifu = value + sd.save(update_fields=['zhifu']) + except Exception: + pass + + @property + def PaymentAccount(self): + """收款账号(存于 UserSensitiveData.skzhanghao)""" + try: + return self.sensitive_data.skzhanghao + except Exception: + return '' + + @PaymentAccount.setter + def PaymentAccount(self, value): + try: + sd = self.sensitive_data + sd.skzhanghao = value + sd.save(update_fields=['skzhanghao']) + except Exception: + pass + + # ── 关联扩展表快捷访问 ── + # DashouProfile / ShopProfile / GuanshiProfile / BossProfile / + # AdminProfile / KefuProfile / ZuzhangProfile / ShenheguanProfile + # 均由 OneToOneField related_name 直接提供反向关联访问 + + def HasRole(self, role_code): + """检查用户是否拥有指定角色(支持角色名或 UserType 值)""" + ROLE_CODE_MAP = { + 'admin': '管理员', 'kefu': '客服', 'guanshi': '负责人', + 'zuzhang': '组长', 'shenheguan': '审核官', 'shop': '商家', + 'dashou': '打手', 'normal': '消费者', + } + target = ROLE_CODE_MAP.get(role_code, role_code) + try: + role_uuids = UserRole.objects.filter( + UserUUID=self.UserUUID + ).values_list('RoleUUID', flat=True) + return Role.objects.filter( + RoleUUID__in=role_uuids, RoleName=target + ).exists() + except Exception: + return False diff --git a/users/migrations/0001_initial.py b/users/migrations/0001_initial.py index 66c6cb2..75fabbe 100644 --- a/users/migrations/0001_initial.py +++ b/users/migrations/0001_initial.py @@ -1,8 +1,11 @@ -# Generated by Django 4.2.27 on 2026-06-17 16:31 +# Generated by Django 4.2.27 on 2026-06-19 18:42 +import datetime from django.conf import settings from django.db import migrations, models import django.db.models.deletion +import gvsdsdk.models +import uuid class Migration(migrations.Migration): @@ -10,7 +13,6 @@ class Migration(migrations.Migration): initial = True dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ @@ -41,6 +43,38 @@ class Migration(migrations.Migration): 'managed': False, }, ), + migrations.CreateModel( + name='User', + fields=[ + ('UserUUID', gvsdsdk.models.UUIDField(binary_length=16, db_column='UserUUID', default=uuid.uuid4, primary_key=True, serialize=False, verbose_name='用户UUID')), + ('UserName', models.CharField(db_column='UserName', max_length=256, unique=True, verbose_name='用户名')), + ('UserPassword', models.CharField(db_column='UserPassword', default='', max_length=60, verbose_name='密码')), + ('UserPositionStatus', models.SmallIntegerField(db_column='UserPositionStatus', default=0, verbose_name='职位状态')), + ('UserPersonalSignature', models.CharField(db_column='UserPersonalSignature', default='', max_length=1024, verbose_name='个人签名')), + ('UserEmail', models.CharField(db_column='UserEmail', default='', max_length=256, verbose_name='邮箱')), + ('UserEmailVerify', models.SmallIntegerField(db_column='UserEmailVerify', default=0, verbose_name='邮箱验证')), + ('UserAccountLicense', models.SmallIntegerField(db_column='UserAccountLicense', default=1, verbose_name='账户许可')), + ('UserGender', models.SmallIntegerField(db_column='UserGender', default=-1, verbose_name='性别')), + ('UserTele', models.CharField(blank=True, db_column='UserTele', max_length=16, null=True, verbose_name='电话')), + ('UserCreateTime', models.DateTimeField(db_column='UserCreateTime', default=datetime.datetime.utcnow, verbose_name='创建时间')), + ('UserLastLoginDate', models.DateTimeField(db_column='UserLastLoginDate', default=datetime.datetime.utcnow, verbose_name='最后登录')), + ('UserUID', models.CharField(blank=True, db_column='UserUID', max_length=7, null=True, unique=True, verbose_name='用户业务ID')), + ('OpenID', models.CharField(blank=True, db_column='OpenID', max_length=64, null=True, unique=True, verbose_name='微信OpenID')), + ('UnionID', models.CharField(blank=True, db_column='UnionID', max_length=64, null=True, verbose_name='微信UnionID')), + ('Avatar', models.CharField(db_column='Avatar', default='a_long/morentouxiang.jpg', max_length=500, verbose_name='头像')), + ('Phone', models.CharField(blank=True, db_column='Phone', max_length=11, null=True, verbose_name='手机号')), + ('PhoneVerified', models.BooleanField(db_column='PhoneVerified', default=False, verbose_name='手机号是否已认证')), + ('IP', models.CharField(blank=True, db_column='IP', max_length=50, null=True, verbose_name='来访用户IP')), + ('IsStaff', models.BooleanField(db_column='IsStaff', default=False, verbose_name='是否员工')), + ('IsSuperuser', models.BooleanField(db_column='IsSuperuser', default=False, verbose_name='是否超级用户')), + ], + options={ + 'verbose_name': '用户', + 'verbose_name_plural': '用户', + 'db_table': 'User', + 'managed': True, + }, + ), migrations.CreateModel( name='OfficialAccountUser', fields=[ @@ -87,6 +121,203 @@ class Migration(migrations.Migration): 'db_table': 'xiugaijilu', }, ), + migrations.CreateModel( + name='UserZuzhang', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('yaoqingma', models.CharField(db_index=True, max_length=20, null=True, verbose_name='组长邀请码')), + ('fenyong_zonge', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='分佣总额(元)')), + ('ketixian_jine', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='可提现金额(元)')), + ('yaoqing_zongshu', models.IntegerField(default=0, verbose_name='邀请总数')), + ('jinri_fenyong', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='今日分佣(元)')), + ('jinyue_fenyong', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='今月分佣(元)')), + ('zhuangtai', models.IntegerField(choices=[(0, '禁用'), (1, '正常')], default=1, verbose_name='账号状态')), + ('haibao_url', models.CharField(blank=True, max_length=500, null=True, verbose_name='推广海报相对URL')), + ('jinri_tixian', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='今日提现金额(元)')), + ('last_tixian_time', models.DateTimeField(blank=True, null=True, verbose_name='最后提现时间')), + ('ewai_tixian_xiane', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='额外提现限额(元)')), + ('kaioi_ewai_tixian', models.BooleanField(default=False, verbose_name='开启额外提现')), + ('kaioi_ewai_fenhong', models.BooleanField(default=False, verbose_name='开启额外分红')), + ('ewai_fenhong_jine', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='额外分红金额(元)')), + ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')), + ('user', models.OneToOneField(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, related_name='ZuzhangProfile', to=settings.AUTH_USER_MODEL, verbose_name='关联用户')), + ], + options={ + 'verbose_name': '组长扩展表', + 'verbose_name_plural': '组长扩展表', + 'db_table': 'user_zuzhang', + }, + ), + migrations.CreateModel( + name='UserShenheguan', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('zhuangtai', models.IntegerField(choices=[(0, '禁用'), (1, '正常')], default=1, verbose_name='账号状态')), + ('shenhe_zhuangtai', models.IntegerField(choices=[(0, '空闲'), (1, '审核中')], default=0, verbose_name='审核官状态')), + ('is_renzheng', models.BooleanField(default=False, verbose_name='是否认证')), + ('shenhe_zongshu', models.IntegerField(default=0, verbose_name='审核总数')), + ('tongguo_zongshu', models.IntegerField(default=0, verbose_name='通过总数')), + ('yue', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='可提现余额')), + ('zonge', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='赚取总额')), + ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')), + ('user', models.OneToOneField(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, related_name='ShenheguanProfile', to=settings.AUTH_USER_MODEL, verbose_name='关联用户')), + ], + options={ + 'verbose_name': '审核官扩展表', + 'verbose_name_plural': '审核官扩展表', + 'db_table': 'user_shenheguan', + }, + ), + migrations.CreateModel( + name='UserShangjia', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('nicheng', models.CharField(db_index=True, max_length=50, unique=True, verbose_name='商家昵称')), + ('zhuangtai', models.IntegerField(choices=[(0, '待审核'), (1, '正常'), (2, '禁用')], default=1, verbose_name='商家状态')), + ('dianhua', models.CharField(max_length=20, null=True, verbose_name='商家电话')), + ('wechat', models.CharField(max_length=50, null=True, verbose_name='商家微信号')), + ('fabu', models.IntegerField(default=0, verbose_name='发布订单总数量')), + ('tuikuan', models.IntegerField(default=0, verbose_name='退款订单总量')), + ('yue', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='商家余额')), + ('chengjiao', models.IntegerField(default=0, verbose_name='商家成交订单总量')), + ('jinridingdan', models.IntegerField(default=0, verbose_name='商家今日订单总量')), + ('jinriliushui', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='商家今日流水')), + ('jinyuedingdan', models.IntegerField(default=0, verbose_name='商家今月订单总量')), + ('jinyueliushui', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='商家今月流水')), + ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), + ('user', models.OneToOneField(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, related_name='ShopProfile', to=settings.AUTH_USER_MODEL, verbose_name='关联用户')), + ], + options={ + 'verbose_name': '商家扩展表', + 'verbose_name_plural': '商家扩展表', + 'db_table': 'user_shangjia', + }, + ), + migrations.CreateModel( + name='UserSensitiveData', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(blank=True, max_length=200, null=True, verbose_name='密码')), + ('zhifu', models.CharField(blank=True, max_length=500, null=True, verbose_name='收款码图片')), + ('skzhanghao', models.CharField(blank=True, max_length=11, null=True, verbose_name='收款账号')), + ('shoujihao_renzheng', models.BooleanField(default=False, verbose_name='手机号是否已认证')), + ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')), + ('user_uuid', models.OneToOneField(db_column='user_uuid_id', on_delete=django.db.models.deletion.CASCADE, related_name='sensitive_data', to=settings.AUTH_USER_MODEL, verbose_name='关联用户')), + ], + options={ + 'verbose_name': '用户敏感数据', + 'verbose_name_plural': '用户敏感数据', + 'db_table': 'user_sensitive_data', + }, + ), + migrations.CreateModel( + name='UserKefu', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('nicheng', models.CharField(max_length=50, verbose_name='客服昵称')), + ('erjimima', models.CharField(max_length=128, verbose_name='二级密码')), + ('zhuangtai', models.IntegerField(choices=[(0, '禁用'), (1, '正常')], default=1, verbose_name='客服状态')), + ('jinrichuli', models.IntegerField(default=0, verbose_name='今日处理订单数')), + ('jinyuechuli', models.IntegerField(default=0, verbose_name='本月处理订单数')), + ('zongchuli', models.IntegerField(default=0, verbose_name='累计处理订单数')), + ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')), + ('user', models.OneToOneField(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, related_name='KefuProfile', to=settings.AUTH_USER_MODEL, verbose_name='关联用户')), + ], + options={ + 'verbose_name': '客服扩展表', + 'verbose_name_plural': '客服扩展表', + 'db_table': 'user_kefu', + }, + ), + migrations.CreateModel( + name='UserGuanshi', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('yaoqingren', models.CharField(db_index=True, max_length=7, null=True, verbose_name='邀请人ID')), + ('yaoqingma', models.CharField(db_index=True, max_length=20, null=True, verbose_name='邀请码')), + ('invite_qrcode_url', models.CharField(blank=True, max_length=500, null=True, verbose_name='邀请码二维码图片URL')), + ('dianhua', models.CharField(max_length=20, null=True, verbose_name='管事电话')), + ('wechat', models.CharField(max_length=50, null=True, verbose_name='管事微信号')), + ('yaogingshuliang', models.IntegerField(default=0, verbose_name='邀请打手总数')), + ('zhuangtai', models.IntegerField(choices=[(0, '禁用'), (1, '正常')], default=1, verbose_name='管事状态')), + ('jinrichongzhi', models.IntegerField(default=0, verbose_name='今日充值打手数量')), + ('jinyuechongzhi', models.IntegerField(default=0, verbose_name='今月充值打手数量')), + ('chongzhifenrun', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='充值分佣总额')), + ('yue', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='可提现余额')), + ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), + ('fenhong_yici', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='首次分红金额')), + ('fenghong_erci_enabled', models.BooleanField(default=False, verbose_name='开启二次分红')), + ('fenghong_erci', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='二次分红金额')), + ('last_tixian_date', models.DateField(blank=True, null=True, verbose_name='最近提现日期')), + ('jinritixian_jine', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='今日已提现金额')), + ('kaioi_ewai_xiane', models.BooleanField(default=False, verbose_name='是否开启额外提现限额')), + ('ewai_xiane', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='额外提现限额(元)')), + ('user', models.OneToOneField(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, related_name='GuanshiProfile', to=settings.AUTH_USER_MODEL, verbose_name='关联用户')), + ], + options={ + 'verbose_name': '管事扩展表', + 'verbose_name_plural': '管事扩展表', + 'db_table': 'user_guanshi', + }, + ), + migrations.CreateModel( + name='UserDashou', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('nicheng', models.CharField(max_length=50, null=True, verbose_name='打手昵称')), + ('chenghao', models.CharField(max_length=50, null=True, verbose_name='打手称号')), + ('zhuangtai', models.IntegerField(default=1, verbose_name='打手状态')), + ('zaixianzhuangtai', models.IntegerField(default=1, verbose_name='打手在线状态')), + ('zhanghaozhuangtai', models.IntegerField(default=1, verbose_name='打手账号状态')), + ('jieshao', models.TextField(null=True, verbose_name='打手介绍')), + ('jiedanzongliang', models.IntegerField(default=0, verbose_name='接单总量')), + ('chengjiaozongliang', models.IntegerField(default=0, verbose_name='成交单总量')), + ('tuikuanliang', models.IntegerField(default=0, verbose_name='退款订单总量')), + ('yue', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='可提现余额')), + ('zonge', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='打单赚取总额')), + ('dianhua', models.CharField(max_length=20, null=True, verbose_name='打手电话')), + ('wechat', models.CharField(max_length=50, null=True, verbose_name='打手微信号')), + ('yaoqingren', models.CharField(db_index=True, max_length=7, null=True, verbose_name='邀请人ID')), + ('jinrijiedan', models.IntegerField(default=0, verbose_name='今日接单数量')), + ('jinrishouyi', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='今日收益金额')), + ('jinyuejiedan', models.IntegerField(default=0, verbose_name='今月接单数量')), + ('jinyueshouyi', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='今月收益金额')), + ('jifen', models.IntegerField(default=0, verbose_name='打手积分')), + ('yajin', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='打手押金')), + ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), + ('last_tixian_date', models.DateField(blank=True, null=True, verbose_name='最近提现日期')), + ('jinritixian_jine', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='今日已提现金额')), + ('kaioi_ewai_xiane', models.BooleanField(default=False, verbose_name='是否开启额外提现限额')), + ('ewai_xiane', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='额外提现限额(元)')), + ('user', models.OneToOneField(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, related_name='DashouProfile', to=settings.AUTH_USER_MODEL, verbose_name='关联用户')), + ], + options={ + 'verbose_name': '打手扩展表', + 'verbose_name_plural': '打手扩展表', + 'db_table': 'user_dashou', + }, + ), + migrations.CreateModel( + name='UserBoss', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('nickname', models.CharField(max_length=50, verbose_name='老板昵称')), + ('zonge', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='消费总额')), + ('alldingdan', models.IntegerField(default=0, verbose_name='订单总数')), + ('alltui', models.IntegerField(default=0, verbose_name='退款总数')), + ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), + ('user', models.OneToOneField(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, related_name='BossProfile', to=settings.AUTH_USER_MODEL, verbose_name='关联用户')), + ], + options={ + 'verbose_name': '老板扩展表', + 'verbose_name_plural': '老板扩展表', + 'db_table': 'user_boss', + }, + ), migrations.CreateModel( name='TixianShenheJilu', fields=[ @@ -192,211 +423,6 @@ class Migration(migrations.Migration): 'unique_together': {('zhouqi', 'tongji_date', 'shenfen', 'paiming')}, }, ), - migrations.CreateModel( - name='UserZuzhang', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('yaoqingma', models.CharField(db_index=True, max_length=20, null=True, verbose_name='组长邀请码')), - ('fenyong_zonge', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='分佣总额(元)')), - ('ketixian_jine', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='可提现金额(元)')), - ('yaoqing_zongshu', models.IntegerField(default=0, verbose_name='邀请总数')), - ('jinri_fenyong', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='今日分佣(元)')), - ('jinyue_fenyong', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='今月分佣(元)')), - ('zhuangtai', models.IntegerField(choices=[(0, '禁用'), (1, '正常')], default=1, verbose_name='账号状态')), - ('haibao_url', models.CharField(blank=True, max_length=500, null=True, verbose_name='推广海报相对URL')), - ('jinri_tixian', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='今日提现金额(元)')), - ('last_tixian_time', models.DateTimeField(blank=True, null=True, verbose_name='最后提现时间')), - ('ewai_tixian_xiane', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='额外提现限额(元)')), - ('kaioi_ewai_tixian', models.BooleanField(default=False, verbose_name='开启额外提现')), - ('kaioi_ewai_fenhong', models.BooleanField(default=False, verbose_name='开启额外分红')), - ('ewai_fenhong_jine', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='额外分红金额(元)')), - ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), - ('update_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')), - ('user', models.OneToOneField(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, related_name='zuzhang_profile', to=settings.AUTH_USER_MODEL, verbose_name='关联用户')), - ], - options={ - 'verbose_name': '组长扩展表', - 'verbose_name_plural': '组长扩展表', - 'db_table': 'user_zuzhang', - 'indexes': [models.Index(fields=['user'], name='user_zuzhan_UserUUI_125e05_idx'), models.Index(fields=['yaoqingma'], name='user_zuzhan_yaoqing_cba91d_idx')], - }, - ), - migrations.CreateModel( - name='UserShenheguan', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('zhuangtai', models.IntegerField(choices=[(0, '禁用'), (1, '正常')], default=1, verbose_name='账号状态')), - ('shenhe_zhuangtai', models.IntegerField(choices=[(0, '空闲'), (1, '审核中')], default=0, verbose_name='审核官状态')), - ('is_renzheng', models.BooleanField(default=False, verbose_name='是否认证')), - ('shenhe_zongshu', models.IntegerField(default=0, verbose_name='审核总数')), - ('tongguo_zongshu', models.IntegerField(default=0, verbose_name='通过总数')), - ('yue', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='可提现余额')), - ('zonge', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='赚取总额')), - ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), - ('update_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')), - ('user', models.OneToOneField(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, related_name='shenheguan_profile', to=settings.AUTH_USER_MODEL, verbose_name='关联用户')), - ], - options={ - 'verbose_name': '审核官扩展表', - 'verbose_name_plural': '审核官扩展表', - 'db_table': 'user_shenheguan', - 'indexes': [models.Index(fields=['user'], name='user_shenhe_UserUUI_bdc981_idx')], - }, - ), - migrations.CreateModel( - name='UserShangjia', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('nicheng', models.CharField(db_index=True, max_length=50, unique=True, verbose_name='商家昵称')), - ('zhuangtai', models.IntegerField(choices=[(0, '待审核'), (1, '正常'), (2, '禁用')], default=1, verbose_name='商家状态')), - ('dianhua', models.CharField(max_length=20, null=True, verbose_name='商家电话')), - ('wechat', models.CharField(max_length=50, null=True, verbose_name='商家微信号')), - ('fabu', models.IntegerField(default=0, verbose_name='发布订单总数量')), - ('tuikuan', models.IntegerField(default=0, verbose_name='退款订单总量')), - ('yue', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='商家余额')), - ('chengjiao', models.IntegerField(default=0, verbose_name='商家成交订单总量')), - ('jinridingdan', models.IntegerField(default=0, verbose_name='商家今日订单总量')), - ('jinriliushui', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='商家今日流水')), - ('jinyuedingdan', models.IntegerField(default=0, verbose_name='商家今月订单总量')), - ('jinyueliushui', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='商家今月流水')), - ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), - ('user', models.OneToOneField(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, related_name='shop_profile', to=settings.AUTH_USER_MODEL, verbose_name='关联用户')), - ], - options={ - 'verbose_name': '商家扩展表', - 'verbose_name_plural': '商家扩展表', - 'db_table': 'user_shangjia', - 'indexes': [models.Index(fields=['user'], name='user_shangj_UserUUI_9d7fad_idx'), models.Index(fields=['nicheng'], name='user_shangj_nicheng_6967bc_idx')], - }, - ), - migrations.CreateModel( - name='UserSensitiveData', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('password', models.CharField(blank=True, max_length=200, null=True, verbose_name='密码')), - ('zhifu', models.CharField(blank=True, max_length=500, null=True, verbose_name='收款码图片')), - ('skzhanghao', models.CharField(blank=True, max_length=11, null=True, verbose_name='收款账号')), - ('shoujihao_renzheng', models.BooleanField(default=False, verbose_name='手机号是否已认证')), - ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), - ('update_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')), - ('user_uuid', models.OneToOneField(db_column='user_uuid_id', on_delete=django.db.models.deletion.CASCADE, related_name='sensitive_data', to=settings.AUTH_USER_MODEL, verbose_name='关联用户')), - ], - options={ - 'verbose_name': '用户敏感数据', - 'verbose_name_plural': '用户敏感数据', - 'db_table': 'user_sensitive_data', - 'indexes': [models.Index(fields=['user_uuid'], name='user_sensit_user_uu_1d562f_idx')], - }, - ), - migrations.CreateModel( - name='UserKefu', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('nicheng', models.CharField(max_length=50, verbose_name='客服昵称')), - ('erjimima', models.CharField(max_length=128, verbose_name='二级密码')), - ('zhuangtai', models.IntegerField(choices=[(0, '禁用'), (1, '正常')], default=1, verbose_name='客服状态')), - ('jinrichuli', models.IntegerField(default=0, verbose_name='今日处理订单数')), - ('jinyuechuli', models.IntegerField(default=0, verbose_name='本月处理订单数')), - ('zongchuli', models.IntegerField(default=0, verbose_name='累计处理订单数')), - ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), - ('update_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')), - ('user', models.OneToOneField(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, related_name='kefu_profile', to=settings.AUTH_USER_MODEL, verbose_name='关联用户')), - ], - options={ - 'verbose_name': '客服扩展表', - 'verbose_name_plural': '客服扩展表', - 'db_table': 'user_kefu', - 'indexes': [models.Index(fields=['user'], name='user_kefu_UserUUI_ccf71c_idx'), models.Index(fields=['zhuangtai'], name='user_kefu_zhuangt_317491_idx')], - }, - ), - migrations.CreateModel( - name='UserGuanshi', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('yaoqingren', models.CharField(db_index=True, max_length=7, null=True, verbose_name='邀请人ID')), - ('yaoqingma', models.CharField(db_index=True, max_length=20, null=True, verbose_name='邀请码')), - ('invite_qrcode_url', models.CharField(blank=True, max_length=500, null=True, verbose_name='邀请码二维码图片URL')), - ('dianhua', models.CharField(max_length=20, null=True, verbose_name='管事电话')), - ('wechat', models.CharField(max_length=50, null=True, verbose_name='管事微信号')), - ('yaogingshuliang', models.IntegerField(default=0, verbose_name='邀请打手总数')), - ('zhuangtai', models.IntegerField(choices=[(0, '禁用'), (1, '正常')], default=1, verbose_name='管事状态')), - ('jinrichongzhi', models.IntegerField(default=0, verbose_name='今日充值打手数量')), - ('jinyuechongzhi', models.IntegerField(default=0, verbose_name='今月充值打手数量')), - ('chongzhifenrun', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='充值分佣总额')), - ('yue', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='可提现余额')), - ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), - ('fenhong_yici', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='首次分红金额')), - ('fenghong_erci_enabled', models.BooleanField(default=False, verbose_name='开启二次分红')), - ('fenghong_erci', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='二次分红金额')), - ('last_tixian_date', models.DateField(blank=True, null=True, verbose_name='最近提现日期')), - ('jinritixian_jine', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='今日已提现金额')), - ('kaioi_ewai_xiane', models.BooleanField(default=False, verbose_name='是否开启额外提现限额')), - ('ewai_xiane', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='额外提现限额(元)')), - ('user', models.OneToOneField(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, related_name='guanshi_profile', to=settings.AUTH_USER_MODEL, verbose_name='关联用户')), - ], - options={ - 'verbose_name': '管事扩展表', - 'verbose_name_plural': '管事扩展表', - 'db_table': 'user_guanshi', - 'indexes': [models.Index(fields=['user'], name='user_guansh_UserUUI_1d9453_idx'), models.Index(fields=['yaoqingma'], name='user_guansh_yaoqing_21d1d4_idx')], - }, - ), - migrations.CreateModel( - name='UserDashou', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('nicheng', models.CharField(max_length=50, null=True, verbose_name='打手昵称')), - ('chenghao', models.CharField(max_length=50, null=True, verbose_name='打手称号')), - ('zhuangtai', models.IntegerField(default=1, verbose_name='打手状态')), - ('zaixianzhuangtai', models.IntegerField(default=1, verbose_name='打手在线状态')), - ('zhanghaozhuangtai', models.IntegerField(default=1, verbose_name='打手账号状态')), - ('jieshao', models.TextField(null=True, verbose_name='打手介绍')), - ('jiedanzongliang', models.IntegerField(default=0, verbose_name='接单总量')), - ('chengjiaozongliang', models.IntegerField(default=0, verbose_name='成交单总量')), - ('tuikuanliang', models.IntegerField(default=0, verbose_name='退款订单总量')), - ('yue', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='可提现余额')), - ('zonge', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='打单赚取总额')), - ('dianhua', models.CharField(max_length=20, null=True, verbose_name='打手电话')), - ('wechat', models.CharField(max_length=50, null=True, verbose_name='打手微信号')), - ('yaoqingren', models.CharField(db_index=True, max_length=7, null=True, verbose_name='邀请人ID')), - ('jinrijiedan', models.IntegerField(default=0, verbose_name='今日接单数量')), - ('jinrishouyi', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='今日收益金额')), - ('jinyuejiedan', models.IntegerField(default=0, verbose_name='今月接单数量')), - ('jinyueshouyi', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='今月收益金额')), - ('jifen', models.IntegerField(default=0, verbose_name='打手积分')), - ('yajin', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='打手押金')), - ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), - ('last_tixian_date', models.DateField(blank=True, null=True, verbose_name='最近提现日期')), - ('jinritixian_jine', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='今日已提现金额')), - ('kaioi_ewai_xiane', models.BooleanField(default=False, verbose_name='是否开启额外提现限额')), - ('ewai_xiane', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='额外提现限额(元)')), - ('user', models.OneToOneField(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, related_name='dashou_profile', to=settings.AUTH_USER_MODEL, verbose_name='关联用户')), - ], - options={ - 'verbose_name': '打手扩展表', - 'verbose_name_plural': '打手扩展表', - 'db_table': 'user_dashou', - 'indexes': [models.Index(fields=['user'], name='user_dashou_UserUUI_92ac5a_idx'), models.Index(fields=['yaoqingren'], name='user_dashou_yaoqing_894658_idx')], - }, - ), - migrations.CreateModel( - name='UserBoss', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('nickname', models.CharField(max_length=50, verbose_name='老板昵称')), - ('zonge', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='消费总额')), - ('alldingdan', models.IntegerField(default=0, verbose_name='订单总数')), - ('alltui', models.IntegerField(default=0, verbose_name='退款总数')), - ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), - ('user', models.OneToOneField(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, related_name='boss_profile', to=settings.AUTH_USER_MODEL, verbose_name='关联用户')), - ], - options={ - 'verbose_name': '老板扩展表', - 'verbose_name_plural': '老板扩展表', - 'db_table': 'user_boss', - 'indexes': [models.Index(fields=['user'], name='user_boss_UserUUI_4579c2_idx')], - }, - ), migrations.CreateModel( name='AdminProfile', fields=[ @@ -405,13 +431,76 @@ class Migration(migrations.Migration): ('wechat', models.CharField(blank=True, max_length=50, verbose_name='管理员微信')), ('yaoqingma', models.CharField(db_index=True, max_length=20, null=True, verbose_name='管理员邀请码')), ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), - ('user', models.OneToOneField(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, related_name='admin_profile', to=settings.AUTH_USER_MODEL, verbose_name='关联用户')), + ('user', models.OneToOneField(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, related_name='AdminProfile', to=settings.AUTH_USER_MODEL, verbose_name='关联用户')), ], options={ 'verbose_name': '管理员扩展表', 'verbose_name_plural': '管理员扩展表', 'db_table': 'admin_profile', - 'indexes': [models.Index(fields=['user'], name='admin_profi_UserUUI_0699ce_idx')], }, ), + migrations.AddIndex( + model_name='user', + index=models.Index(fields=['UserUID'], name='User_UserUID_a656ea_idx'), + ), + migrations.AddIndex( + model_name='user', + index=models.Index(fields=['OpenID'], name='User_OpenID_2a920d_idx'), + ), + migrations.AddIndex( + model_name='userzuzhang', + index=models.Index(fields=['user'], name='user_zuzhan_UserUUI_125e05_idx'), + ), + migrations.AddIndex( + model_name='userzuzhang', + index=models.Index(fields=['yaoqingma'], name='user_zuzhan_yaoqing_cba91d_idx'), + ), + migrations.AddIndex( + model_name='usershenheguan', + index=models.Index(fields=['user'], name='user_shenhe_UserUUI_bdc981_idx'), + ), + migrations.AddIndex( + model_name='usershangjia', + index=models.Index(fields=['user'], name='user_shangj_UserUUI_9d7fad_idx'), + ), + migrations.AddIndex( + model_name='usershangjia', + index=models.Index(fields=['nicheng'], name='user_shangj_nicheng_6967bc_idx'), + ), + migrations.AddIndex( + model_name='usersensitivedata', + index=models.Index(fields=['user_uuid'], name='user_sensit_user_uu_1d562f_idx'), + ), + migrations.AddIndex( + model_name='userkefu', + index=models.Index(fields=['user'], name='user_kefu_UserUUI_ccf71c_idx'), + ), + migrations.AddIndex( + model_name='userkefu', + index=models.Index(fields=['zhuangtai'], name='user_kefu_zhuangt_317491_idx'), + ), + migrations.AddIndex( + model_name='userguanshi', + index=models.Index(fields=['user'], name='user_guansh_UserUUI_1d9453_idx'), + ), + migrations.AddIndex( + model_name='userguanshi', + index=models.Index(fields=['yaoqingma'], name='user_guansh_yaoqing_21d1d4_idx'), + ), + migrations.AddIndex( + model_name='userdashou', + index=models.Index(fields=['user'], name='user_dashou_UserUUI_92ac5a_idx'), + ), + migrations.AddIndex( + model_name='userdashou', + index=models.Index(fields=['yaoqingren'], name='user_dashou_yaoqing_894658_idx'), + ), + migrations.AddIndex( + model_name='userboss', + index=models.Index(fields=['user'], name='user_boss_UserUUI_4579c2_idx'), + ), + migrations.AddIndex( + model_name='adminprofile', + index=models.Index(fields=['user'], name='admin_profi_UserUUI_0699ce_idx'), + ), ] diff --git a/users/migrations/0002_alter_adminprofile_user_alter_userboss_user_and_more.py b/users/migrations/0002_alter_adminprofile_user_alter_userboss_user_and_more.py deleted file mode 100644 index f0985c0..0000000 --- a/users/migrations/0002_alter_adminprofile_user_alter_userboss_user_and_more.py +++ /dev/null @@ -1,56 +0,0 @@ -# Generated by Django 4.2.27 on 2026-06-19 01:08 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('users', '0001_initial'), - ] - - operations = [ - migrations.AlterField( - model_name='adminprofile', - name='user', - field=models.OneToOneField(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, related_name='AdminProfile', to=settings.AUTH_USER_MODEL, verbose_name='关联用户'), - ), - migrations.AlterField( - model_name='userboss', - name='user', - field=models.OneToOneField(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, related_name='BossProfile', to=settings.AUTH_USER_MODEL, verbose_name='关联用户'), - ), - migrations.AlterField( - model_name='userdashou', - name='user', - field=models.OneToOneField(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, related_name='DashouProfile', to=settings.AUTH_USER_MODEL, verbose_name='关联用户'), - ), - migrations.AlterField( - model_name='userguanshi', - name='user', - field=models.OneToOneField(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, related_name='GuanshiProfile', to=settings.AUTH_USER_MODEL, verbose_name='关联用户'), - ), - migrations.AlterField( - model_name='userkefu', - name='user', - field=models.OneToOneField(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, related_name='KefuProfile', to=settings.AUTH_USER_MODEL, verbose_name='关联用户'), - ), - migrations.AlterField( - model_name='usershangjia', - name='user', - field=models.OneToOneField(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, related_name='ShopProfile', to=settings.AUTH_USER_MODEL, verbose_name='关联用户'), - ), - migrations.AlterField( - model_name='usershenheguan', - name='user', - field=models.OneToOneField(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, related_name='ShenheguanProfile', to=settings.AUTH_USER_MODEL, verbose_name='关联用户'), - ), - migrations.AlterField( - model_name='userzuzhang', - name='user', - field=models.OneToOneField(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, related_name='ZuzhangProfile', to=settings.AUTH_USER_MODEL, verbose_name='关联用户'), - ), - ] diff --git a/users/models.py b/users/models.py index 19e0eff..8547de9 100644 --- a/users/models.py +++ b/users/models.py @@ -91,7 +91,7 @@ class OfficialAccountUser(QModel): # ==================== 老板扩展表 ==================== class UserBoss(QModel): - user = models.OneToOneField('gvsdsdk.User', on_delete=models.CASCADE, related_name='BossProfile', + user = models.OneToOneField('users.User', on_delete=models.CASCADE, related_name='BossProfile', verbose_name='关联用户', db_column='UserUUID') nickname = models.CharField(max_length=50, verbose_name='老板昵称') zonge = models.DecimalField(max_digits=12, decimal_places=2, default=0.00, verbose_name='消费总额') @@ -108,7 +108,7 @@ class UserBoss(QModel): # ==================== 打手扩展表 ==================== class UserDashou(QModel): - user = models.OneToOneField('gvsdsdk.User', on_delete=models.CASCADE, related_name='DashouProfile', + user = models.OneToOneField('users.User', on_delete=models.CASCADE, related_name='DashouProfile', verbose_name='关联用户', db_column='UserUUID') nicheng = models.CharField(max_length=50, null=True, verbose_name='打手昵称') chenghao = models.CharField(max_length=50, null=True,verbose_name='打手称号') @@ -152,7 +152,7 @@ class UserDashou(QModel): # ==================== 商家扩展表 ==================== class UserShangjia(QModel): - user = models.OneToOneField('gvsdsdk.User', on_delete=models.CASCADE, related_name='ShopProfile', + user = models.OneToOneField('users.User', on_delete=models.CASCADE, related_name='ShopProfile', verbose_name='关联用户', db_column='UserUUID') nicheng = models.CharField(max_length=50, unique=True, db_index=True, verbose_name='商家昵称') zhuangtai = models.IntegerField(choices=[(0, '待审核'), (1, '正常'), (2, '禁用')], default=1, @@ -181,7 +181,7 @@ class UserShangjia(QModel): # ==================== 管事扩展表 ==================== class UserGuanshi(QModel): - user = models.OneToOneField('gvsdsdk.User', on_delete=models.CASCADE, related_name='GuanshiProfile', + user = models.OneToOneField('users.User', on_delete=models.CASCADE, related_name='GuanshiProfile', verbose_name='关联用户', db_column='UserUUID') yaoqingren = models.CharField(max_length=7,null=True, db_index=True, verbose_name='邀请人ID') yaoqingma = models.CharField(max_length=20,null=True,db_index=True, verbose_name='邀请码') @@ -224,7 +224,7 @@ class UserGuanshi(QModel): class UserZuzhang(QModel): """组长扩展表(与UserMain一对一关联)""" user = models.OneToOneField( - 'gvsdsdk.User', + 'users.User', on_delete=models.CASCADE, related_name='ZuzhangProfile', verbose_name='关联用户', @@ -278,7 +278,7 @@ class UserZuzhang(QModel): class UserShenheguan(QModel): """审核官扩展表(与UserMain一对一关联)""" - user = models.OneToOneField('gvsdsdk.User', on_delete=models.CASCADE, related_name='ShenheguanProfile', verbose_name='关联用户', db_index=True, db_column='UserUUID') + user = models.OneToOneField('users.User', on_delete=models.CASCADE, related_name='ShenheguanProfile', verbose_name='关联用户', db_index=True, db_column='UserUUID') zhuangtai = models.IntegerField(choices=[(0, '禁用'), (1, '正常')], default=1, verbose_name='账号状态') shenhe_zhuangtai = models.IntegerField(choices=[(0, '空闲'), (1, '审核中')], default=0, verbose_name='审核官状态') is_renzheng = models.BooleanField(default=False, verbose_name='是否认证') @@ -298,7 +298,7 @@ class UserShenheguan(QModel): # ==================== 管理员扩展表 ==================== class AdminProfile(QModel): - user = models.OneToOneField('gvsdsdk.User', on_delete=models.CASCADE, related_name='AdminProfile', + user = models.OneToOneField('users.User', on_delete=models.CASCADE, related_name='AdminProfile', verbose_name='关联用户', db_column='UserUUID') password = models.CharField(max_length=255, verbose_name='密码') wechat = models.CharField(max_length=50, blank=True, verbose_name='管理员微信') @@ -313,7 +313,7 @@ class AdminProfile(QModel): class UserKefu(QModel): - user = models.OneToOneField('gvsdsdk.User', on_delete=models.CASCADE, related_name='KefuProfile', verbose_name='关联用户', db_column='UserUUID') + user = models.OneToOneField('users.User', on_delete=models.CASCADE, related_name='KefuProfile', verbose_name='关联用户', db_column='UserUUID') nicheng = models.CharField(max_length=50, verbose_name='客服昵称') erjimima = models.CharField(max_length=128, verbose_name='二级密码') zhuangtai = models.IntegerField(choices=[(0, '禁用'), (1, '正常')], default=1, verbose_name='客服状态') @@ -604,7 +604,7 @@ class RankingRecord(QModel): class UserSensitiveData(QModel): """用户敏感数据表——独立存储敏感信息,不继承 gvsdsdk""" user_uuid = models.OneToOneField( - 'gvsdsdk.User', + 'users.User', on_delete=models.CASCADE, related_name='sensitive_data', verbose_name='关联用户', @@ -627,3 +627,9 @@ class UserSensitiveData(QModel): return f'敏感数据-{self.user_uuid_id}' +# === 业务用户模型注册 === +# 导入业务子类,使 Django app registry 注册具体 User 模型(users.User)。 +# 放在文件末尾以避免循环导入:此时本模块所有类已定义完毕。 +from users.business_models import User as _BusinessUser # noqa: E402,F401 + + diff --git a/users/paihang_views.py b/users/paihang_views.py index 57dfb26..37399c4 100644 --- a/users/paihang_views.py +++ b/users/paihang_views.py @@ -18,7 +18,7 @@ from backend.models import ( MerchantDailyStats, ) from users.models import UserDashou, UserShangjia, UserBoss, UserGuanshi -from gvsdsdk.models import User +from users.business_models import User logger = logging.getLogger(__name__) diff --git a/users/ranking_tasks.py b/users/ranking_tasks.py index f1c343f..cca612f 100644 --- a/users/ranking_tasks.py +++ b/users/ranking_tasks.py @@ -15,7 +15,7 @@ from users.models import ( UserDashou, UserShangjia, UserGuanshi, UserBoss, RankingRecord ) -from gvsdsdk.models import User +from users.business_models import User logger = logging.getLogger(__name__) diff --git a/users/tixian_shenhe_services.py b/users/tixian_shenhe_services.py index d7a90ec..866cafe 100644 --- a/users/tixian_shenhe_services.py +++ b/users/tixian_shenhe_services.py @@ -45,7 +45,7 @@ from .models import ( UserShangjia, UserZuzhang, ) -from gvsdsdk.models import User +from users.business_models import User from orders.utils import update_daily_payout diff --git a/users/views.py b/users/views.py index f02a25e..806f1d3 100644 --- a/users/views.py +++ b/users/views.py @@ -65,7 +65,7 @@ from .models import ( TixianAutoRecord, TixianShenheJilu, Tixianjilu, Xiugaijilu, RankingRecord ) -from gvsdsdk.models import User +from users.business_models import User from .tixian_shenhe_services import ( load_audit_meta_map, refund_balance, sync_audit_and_jilu_status, mark_transfer_success, release_collect_quota_for_record, @@ -219,7 +219,7 @@ class WechatMiniProgramLoginView(APIView): if created: UserBoss.query.create(user=user_main, nickname='板板大人') # 新用户默认分配消费者角色 - from gvsdsdk.models import UserRole, Role + from users.business_models import UserRole, Role normal_role = Role.objects.filter(RoleName='消费者').first() if normal_role: UserRole.objects.create( diff --git a/utils/chat_utils.py b/utils/chat_utils.py index 58375e6..36f97e2 100644 --- a/utils/chat_utils.py +++ b/utils/chat_utils.py @@ -5,7 +5,7 @@ import requests from django.conf import settings from orders.models import Order, PlatformOrderExt, MerchantOrderExt from users.models import UserDashou, UserBoss, UserShangjia -from gvsdsdk.models import User +from users.business_models import User logger = logging.getLogger('chat_utils')