You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
109 lines
3.3 KiB
Python
109 lines
3.3 KiB
Python
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()
|