from iti.applications.extensions import db from iti.applications.common.crud import BaseModelMixin from iti.applications.common.utils import BaseSchema from apiflask.fields import String, Integer class SysUserAttribute(BaseModelMixin): """ 用户扩展属性表 (Key-Value 列存储模式) """ __tablename__ = "sys_user_attribute" user_id = db.Column( db.String(36), db.ForeignKey("sys_user.id", ondelete="CASCADE"), nullable=False, index=True, comment="用户ID", ) attr_group = db.Column( db.String(64), nullable=False, index=True, comment="属性分组(如: erp, custom)" ) attr_key = db.Column(db.String(128), nullable=False, comment="属性键") attr_value = db.Column(db.Text, nullable=True, comment="属性值") attr_type = db.Column( db.String(32), nullable=False, default="string", comment="值类型(string/int/float/bool/json/encrypted)", ) description = db.Column(db.String(255), nullable=True, comment="属性描述") sort = db.Column(db.Integer, nullable=False, default=0, comment="排序") # 关系 user = db.relationship("User", back_populates="user_attributes") # 联合唯一索引:一个用户的同一分组下不能有重复的键 __table_args__ = ( db.Index("idx_user_group_key", "user_id", "attr_group", "attr_key"), db.UniqueConstraint( "user_id", "attr_group", "attr_key", name="uk_user_group_key" ), ) def get_typed_value(self): """ 根据 attr_type 返回类型化的值 """ if self.attr_value is None: return None if self.attr_type == "int": try: return int(self.attr_value) except (ValueError, TypeError): return None elif self.attr_type == "float": try: return float(self.attr_value) except (ValueError, TypeError): return None elif self.attr_type == "bool": return self.attr_value.lower() in ("true", "1", "yes", "on") elif self.attr_type == "json": import json try: return json.loads(self.attr_value) except (ValueError, TypeError): return None elif self.attr_type == "encrypted": # 加密字段,返回时不解密(需要时在业务层处理) return "******" else: # string return self.attr_value def set_typed_value(self, value): """ 根据 attr_type 设置类型化的值 """ if value is None: self.attr_value = None return if self.attr_type == "json": import json self.attr_value = json.dumps(value, ensure_ascii=False) elif self.attr_type == "bool": self.attr_value = "true" if value else "false" else: self.attr_value = str(value) class SysUserAttributeSchema(BaseSchema): """ 用户扩展属性 Schema """ id = String() user_id = String(data_key="userId") attr_group = String(data_key="attrGroup") attr_key = String(data_key="attrKey") attr_value = String(data_key="attrValue") attr_type = String(data_key="attrType") description = String() sort = Integer()