"""业务用户模型——继承 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='是否超级用户') ClubID = models.CharField( max_length=16, default='xq', db_column='ClubID', verbose_name='所属俱乐部', null=True, blank=True, ) 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