Merge branch 'temp' into treebeard
commit
d6f8c707a1
|
@ -10,7 +10,7 @@ def is_tenants_mode():
|
|||
判断是否为租户模式
|
||||
:return:
|
||||
"""
|
||||
return hasattr(connection, 'tenant') and connection.tenant.schema_name
|
||||
return hasattr(connection, "tenant") and connection.tenant.schema_name
|
||||
|
||||
|
||||
# ================================================= #
|
||||
|
@ -18,27 +18,37 @@ def is_tenants_mode():
|
|||
# ================================================= #
|
||||
def _get_all_dictionary():
|
||||
from dvadmin.system.models import Dictionary
|
||||
|
||||
queryset = Dictionary.objects.filter(status=True, is_value=False)
|
||||
data = []
|
||||
for instance in queryset:
|
||||
data.append({
|
||||
"id": instance.id,
|
||||
"value": instance.value,
|
||||
"children": list(Dictionary.objects.filter(parent=instance.id).filter(status=1).
|
||||
values('label', 'value', 'type', 'color'))
|
||||
})
|
||||
data.append(
|
||||
{
|
||||
"id": instance.id,
|
||||
"value": instance.value,
|
||||
"children": list(
|
||||
instance.get_children()
|
||||
.filter(status=1)
|
||||
.values("label", "value", "type", "color")
|
||||
),
|
||||
}
|
||||
)
|
||||
return {ele.get("value"): ele for ele in data}
|
||||
|
||||
|
||||
def _get_all_system_config():
|
||||
data = {}
|
||||
from dvadmin.system.models import SystemConfig
|
||||
system_config_obj = SystemConfig.objects.filter(status=True, parent_id__isnull=False).values(
|
||||
'parent__key', 'key', 'value', 'form_item_type').order_by('sort')
|
||||
|
||||
system_config_obj = (
|
||||
SystemConfig.objects.filter(status=True, parent__isnull=False)
|
||||
.values("parent__key", "key", "value", "form_item_type")
|
||||
.order_by("sort")
|
||||
)
|
||||
for system_config in system_config_obj:
|
||||
value = system_config.get('value') or ''
|
||||
if value and system_config.get('form_item_type') == 7:
|
||||
value = value[0].get('url')
|
||||
value = system_config.get("value") or ""
|
||||
if value and system_config.get("form_item_type") == 7:
|
||||
value = value[0].get("url")
|
||||
data[f"{system_config.get('parent__key')}.{system_config.get('key')}"] = value
|
||||
return data
|
||||
|
||||
|
@ -51,9 +61,12 @@ def init_dictionary():
|
|||
try:
|
||||
if is_tenants_mode():
|
||||
from django_tenants.utils import tenant_context, get_tenant_model
|
||||
|
||||
for tenant in get_tenant_model().objects.filter():
|
||||
with tenant_context(tenant):
|
||||
settings.DICTIONARY_CONFIG[connection.tenant.schema_name] = _get_all_dictionary()
|
||||
settings.DICTIONARY_CONFIG[
|
||||
connection.tenant.schema_name
|
||||
] = _get_all_dictionary()
|
||||
else:
|
||||
settings.DICTIONARY_CONFIG = _get_all_dictionary()
|
||||
print("初始化字典配置完成")
|
||||
|
@ -72,9 +85,12 @@ def init_system_config():
|
|||
|
||||
if is_tenants_mode():
|
||||
from django_tenants.utils import tenant_context, get_tenant_model
|
||||
|
||||
for tenant in get_tenant_model().objects.filter():
|
||||
with tenant_context(tenant):
|
||||
settings.SYSTEM_CONFIG[connection.tenant.schema_name] = _get_all_system_config()
|
||||
settings.SYSTEM_CONFIG[
|
||||
connection.tenant.schema_name
|
||||
] = _get_all_system_config()
|
||||
else:
|
||||
settings.SYSTEM_CONFIG = _get_all_system_config()
|
||||
print("初始化系统配置完成")
|
||||
|
@ -90,9 +106,12 @@ def refresh_dictionary():
|
|||
"""
|
||||
if is_tenants_mode():
|
||||
from django_tenants.utils import tenant_context, get_tenant_model
|
||||
|
||||
for tenant in get_tenant_model().objects.filter():
|
||||
with tenant_context(tenant):
|
||||
settings.DICTIONARY_CONFIG[connection.tenant.schema_name] = _get_all_dictionary()
|
||||
settings.DICTIONARY_CONFIG[
|
||||
connection.tenant.schema_name
|
||||
] = _get_all_dictionary()
|
||||
else:
|
||||
settings.DICTIONARY_CONFIG = _get_all_dictionary()
|
||||
|
||||
|
@ -104,9 +123,12 @@ def refresh_system_config():
|
|||
"""
|
||||
if is_tenants_mode():
|
||||
from django_tenants.utils import tenant_context, get_tenant_model
|
||||
|
||||
for tenant in get_tenant_model().objects.filter():
|
||||
with tenant_context(tenant):
|
||||
settings.SYSTEM_CONFIG[connection.tenant.schema_name] = _get_all_system_config()
|
||||
settings.SYSTEM_CONFIG[
|
||||
connection.tenant.schema_name
|
||||
] = _get_all_system_config()
|
||||
else:
|
||||
settings.SYSTEM_CONFIG = _get_all_system_config()
|
||||
|
||||
|
@ -121,7 +143,9 @@ def get_dictionary_config(schema_name=None):
|
|||
:return:
|
||||
"""
|
||||
if is_tenants_mode():
|
||||
dictionary_config = settings.DICTIONARY_CONFIG[schema_name or connection.tenant.schema_name]
|
||||
dictionary_config = settings.DICTIONARY_CONFIG[
|
||||
schema_name or connection.tenant.schema_name
|
||||
]
|
||||
else:
|
||||
dictionary_config = settings.DICTIONARY_CONFIG
|
||||
return dictionary_config or {}
|
||||
|
@ -165,7 +189,9 @@ def get_system_config(schema_name=None):
|
|||
:return:
|
||||
"""
|
||||
if is_tenants_mode():
|
||||
dictionary_config = settings.SYSTEM_CONFIG[schema_name or connection.tenant.schema_name]
|
||||
dictionary_config = settings.SYSTEM_CONFIG[
|
||||
schema_name or connection.tenant.schema_name
|
||||
]
|
||||
else:
|
||||
dictionary_config = settings.SYSTEM_CONFIG
|
||||
return dictionary_config or {}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# #################### start #######################
|
||||
# AREPL for python调试,导入项目依赖 (可禁用)
|
||||
BASE_DIR = Path(__file__).parent.parent
|
||||
VENV_DIR = Path.joinpath(BASE_DIR, "__pypackages__", "3.8", "lib") # PDM
|
||||
# print(f"{BASE_DIR=}")
|
||||
# 确认BASE_DIR无误后添加如下路径至系统路径
|
||||
for dir in [str(BASE_DIR), str(VENV_DIR)]:
|
||||
if dir not in sys.path:
|
||||
sys.path.insert(1, dir)
|
||||
# #################### end #########################
|
||||
|
||||
import django
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "application.settings")
|
||||
django.setup()
|
|
@ -1,6 +1,9 @@
|
|||
import hashlib
|
||||
import os
|
||||
|
||||
from treebeard.mp_tree import MP_Node
|
||||
from treebeard.al_tree import AL_Node
|
||||
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.db import models
|
||||
|
||||
|
@ -14,62 +17,107 @@ STATUS_CHOICES = (
|
|||
|
||||
|
||||
class Users(AbstractUser, CoreModel):
|
||||
username = models.CharField(max_length=150, unique=True, db_index=True, verbose_name='用户账号', help_text="用户账号")
|
||||
email = models.EmailField(max_length=255, verbose_name="邮箱", null=True, blank=True, help_text="邮箱")
|
||||
mobile = models.CharField(max_length=255, verbose_name="电话", null=True, blank=True, help_text="电话")
|
||||
avatar = models.CharField(max_length=255, verbose_name="头像", null=True, blank=True, help_text="头像")
|
||||
username = models.CharField(
|
||||
max_length=150,
|
||||
unique=True,
|
||||
db_index=True,
|
||||
verbose_name="用户账号",
|
||||
help_text="用户账号",
|
||||
)
|
||||
email = models.EmailField(
|
||||
max_length=255, verbose_name="邮箱", null=True, blank=True, help_text="邮箱"
|
||||
)
|
||||
mobile = models.CharField(
|
||||
max_length=255, verbose_name="电话", null=True, blank=True, help_text="电话"
|
||||
)
|
||||
avatar = models.CharField(
|
||||
max_length=255, verbose_name="头像", null=True, blank=True, help_text="头像"
|
||||
)
|
||||
name = models.CharField(max_length=40, verbose_name="姓名", help_text="姓名")
|
||||
GENDER_CHOICES = (
|
||||
(0, "未知"),
|
||||
(1, "男"),
|
||||
(2, "女"),
|
||||
)
|
||||
gender = models.IntegerField(choices=GENDER_CHOICES, default=0, verbose_name="性别", null=True, blank=True,
|
||||
help_text="性别")
|
||||
gender = models.IntegerField(
|
||||
choices=GENDER_CHOICES,
|
||||
default=0,
|
||||
verbose_name="性别",
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="性别",
|
||||
)
|
||||
USER_TYPE = (
|
||||
(0, "后台用户"),
|
||||
(1, "前台用户"),
|
||||
)
|
||||
user_type = models.IntegerField(choices=USER_TYPE, default=0, verbose_name="用户类型", null=True, blank=True,
|
||||
help_text="用户类型")
|
||||
post = models.ManyToManyField(to='Post', verbose_name='关联岗位', db_constraint=False, help_text="关联岗位")
|
||||
role = models.ManyToManyField(to='Role', verbose_name='关联角色', db_constraint=False, help_text="关联角色")
|
||||
dept = models.ForeignKey(to='Dept', verbose_name='所属部门', on_delete=models.PROTECT, db_constraint=False, null=True,
|
||||
blank=True, help_text="关联部门")
|
||||
user_type = models.IntegerField(
|
||||
choices=USER_TYPE,
|
||||
default=0,
|
||||
verbose_name="用户类型",
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="用户类型",
|
||||
)
|
||||
post = models.ManyToManyField(
|
||||
to="Post", verbose_name="关联岗位", db_constraint=False, help_text="关联岗位"
|
||||
)
|
||||
role = models.ManyToManyField(
|
||||
to="Role", verbose_name="关联角色", db_constraint=False, help_text="关联角色"
|
||||
)
|
||||
dept = models.ForeignKey(
|
||||
to="Dept",
|
||||
verbose_name="所属部门",
|
||||
on_delete=models.PROTECT,
|
||||
db_constraint=False,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="关联部门",
|
||||
)
|
||||
|
||||
def set_password(self, raw_password):
|
||||
super().set_password(hashlib.md5(raw_password.encode(encoding='UTF-8')).hexdigest())
|
||||
super().set_password(
|
||||
hashlib.md5(raw_password.encode(encoding="UTF-8")).hexdigest()
|
||||
)
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "system_users"
|
||||
verbose_name = '用户表'
|
||||
verbose_name = "用户表"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ('-create_datetime',)
|
||||
ordering = ("-create_datetime",)
|
||||
|
||||
|
||||
class Post(CoreModel):
|
||||
name = models.CharField(null=False, max_length=64, verbose_name="岗位名称", help_text="岗位名称")
|
||||
name = models.CharField(
|
||||
null=False, max_length=64, verbose_name="岗位名称", help_text="岗位名称"
|
||||
)
|
||||
code = models.CharField(max_length=32, verbose_name="岗位编码", help_text="岗位编码")
|
||||
sort = models.IntegerField(default=1, verbose_name="岗位顺序", help_text="岗位顺序")
|
||||
STATUS_CHOICES = (
|
||||
(0, "离职"),
|
||||
(1, "在职"),
|
||||
)
|
||||
status = models.IntegerField(choices=STATUS_CHOICES, default=1, verbose_name="岗位状态", help_text="岗位状态")
|
||||
status = models.IntegerField(
|
||||
choices=STATUS_CHOICES, default=1, verbose_name="岗位状态", help_text="岗位状态"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "system_post"
|
||||
verbose_name = '岗位表'
|
||||
verbose_name = "岗位表"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ('sort',)
|
||||
ordering = ("sort",)
|
||||
|
||||
|
||||
class Role(CoreModel):
|
||||
name = models.CharField(max_length=64, verbose_name="角色名称", help_text="角色名称")
|
||||
key = models.CharField(max_length=64, unique=True, verbose_name="权限字符", help_text="权限字符")
|
||||
key = models.CharField(
|
||||
max_length=64, unique=True, verbose_name="权限字符", help_text="权限字符"
|
||||
)
|
||||
sort = models.IntegerField(default=1, verbose_name="角色顺序", help_text="角色顺序")
|
||||
status = models.BooleanField(default=True, verbose_name="角色状态", help_text="角色状态")
|
||||
admin = models.BooleanField(default=False, verbose_name="是否为admin", help_text="是否为admin")
|
||||
admin = models.BooleanField(
|
||||
default=False, verbose_name="是否为admin", help_text="是否为admin"
|
||||
)
|
||||
DATASCOPE_CHOICES = (
|
||||
(0, "仅本人数据权限"),
|
||||
(1, "本部门及以下数据权限"),
|
||||
|
@ -77,67 +125,119 @@ class Role(CoreModel):
|
|||
(3, "全部数据权限"),
|
||||
(4, "自定数据权限"),
|
||||
)
|
||||
data_range = models.IntegerField(default=0, choices=DATASCOPE_CHOICES, verbose_name="数据权限范围", help_text="数据权限范围")
|
||||
data_range = models.IntegerField(
|
||||
default=0, choices=DATASCOPE_CHOICES, verbose_name="数据权限范围", help_text="数据权限范围"
|
||||
)
|
||||
remark = models.TextField(verbose_name="备注", help_text="备注", null=True, blank=True)
|
||||
dept = models.ManyToManyField(to='Dept', verbose_name='数据权限-关联部门', db_constraint=False, help_text="数据权限-关联部门")
|
||||
menu = models.ManyToManyField(to='Menu', verbose_name='关联菜单', db_constraint=False, help_text="关联菜单")
|
||||
permission = models.ManyToManyField(to='MenuButton', verbose_name='关联菜单的接口按钮', db_constraint=False,
|
||||
help_text="关联菜单的接口按钮")
|
||||
dept = models.ManyToManyField(
|
||||
to="Dept", verbose_name="数据权限-关联部门", db_constraint=False, help_text="数据权限-关联部门"
|
||||
)
|
||||
menu = models.ManyToManyField(
|
||||
to="Menu", verbose_name="关联菜单", db_constraint=False, help_text="关联菜单"
|
||||
)
|
||||
permission = models.ManyToManyField(
|
||||
to="MenuButton",
|
||||
verbose_name="关联菜单的接口按钮",
|
||||
db_constraint=False,
|
||||
help_text="关联菜单的接口按钮",
|
||||
)
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + 'system_role'
|
||||
verbose_name = '角色表'
|
||||
db_table = table_prefix + "system_role"
|
||||
verbose_name = "角色表"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ('sort',)
|
||||
ordering = ("sort",)
|
||||
|
||||
|
||||
class Dept(CoreModel):
|
||||
class Dept(AL_Node, CoreModel):
|
||||
name = models.CharField(max_length=64, verbose_name="部门名称", help_text="部门名称")
|
||||
sort = models.IntegerField(default=1, verbose_name="显示排序", help_text="显示排序")
|
||||
owner = models.CharField(max_length=32, verbose_name="负责人", null=True, blank=True, help_text="负责人")
|
||||
phone = models.CharField(max_length=32, verbose_name="联系电话", null=True, blank=True, help_text="联系电话")
|
||||
email = models.EmailField(max_length=32, verbose_name="邮箱", null=True, blank=True, help_text="邮箱")
|
||||
status = models.BooleanField(default=True, verbose_name="部门状态", null=True, blank=True,
|
||||
help_text="部门状态")
|
||||
parent = models.ForeignKey(to='Dept', on_delete=models.CASCADE, default=None, verbose_name="上级部门",
|
||||
db_constraint=False, null=True, blank=True, help_text="上级部门")
|
||||
owner = models.CharField(
|
||||
max_length=32, verbose_name="负责人", null=True, blank=True, help_text="负责人"
|
||||
)
|
||||
phone = models.CharField(
|
||||
max_length=32, verbose_name="联系电话", null=True, blank=True, help_text="联系电话"
|
||||
)
|
||||
email = models.EmailField(
|
||||
max_length=32, verbose_name="邮箱", null=True, blank=True, help_text="邮箱"
|
||||
)
|
||||
status = models.BooleanField(
|
||||
default=True, verbose_name="部门状态", null=True, blank=True, help_text="部门状态"
|
||||
)
|
||||
parent = models.ForeignKey(
|
||||
to="Dept",
|
||||
on_delete=models.CASCADE,
|
||||
default=None,
|
||||
verbose_name="上级部门",
|
||||
db_constraint=False,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="上级部门",
|
||||
)
|
||||
|
||||
node_order_by = ["sort", "name"]
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "system_dept"
|
||||
verbose_name = '部门表'
|
||||
verbose_name = "部门表"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ('sort',)
|
||||
ordering = ("sort",)
|
||||
|
||||
|
||||
class Menu(CoreModel):
|
||||
parent = models.ForeignKey(to='Menu', on_delete=models.CASCADE, verbose_name="上级菜单", null=True, blank=True,
|
||||
db_constraint=False, help_text="上级菜单")
|
||||
icon = models.CharField(max_length=64, verbose_name="菜单图标", null=True, blank=True, help_text="菜单图标")
|
||||
class Menu(MP_Node, CoreModel):
|
||||
icon = models.CharField(
|
||||
max_length=64, verbose_name="菜单图标", null=True, blank=True, help_text="菜单图标"
|
||||
)
|
||||
name = models.CharField(max_length=64, verbose_name="菜单名称", help_text="菜单名称")
|
||||
sort = models.IntegerField(default=1, verbose_name="显示排序", null=True, blank=True, help_text="显示排序")
|
||||
sort = models.IntegerField(
|
||||
default=1, verbose_name="显示排序", null=True, blank=True, help_text="显示排序"
|
||||
)
|
||||
ISLINK_CHOICES = (
|
||||
(0, "否"),
|
||||
(1, "是"),
|
||||
)
|
||||
is_link = models.BooleanField(default=False, verbose_name="是否外链", help_text="是否外链")
|
||||
is_catalog = models.BooleanField(default=False, verbose_name="是否目录", help_text="是否目录")
|
||||
web_path = models.CharField(max_length=128, verbose_name="路由地址", null=True, blank=True, help_text="路由地址")
|
||||
component = models.CharField(max_length=128, verbose_name="组件地址", null=True, blank=True, help_text="组件地址")
|
||||
component_name = models.CharField(max_length=50, verbose_name="组件名称", null=True, blank=True, help_text="组件名称")
|
||||
status = models.BooleanField(default=True, blank=True, verbose_name="菜单状态", help_text="菜单状态")
|
||||
cache = models.BooleanField(default=False, blank=True, verbose_name="是否页面缓存", help_text="是否页面缓存")
|
||||
visible = models.BooleanField(default=True, blank=True, verbose_name="侧边栏中是否显示", help_text="侧边栏中是否显示")
|
||||
is_catalog = models.BooleanField(
|
||||
default=False, verbose_name="是否目录", help_text="是否目录"
|
||||
)
|
||||
web_path = models.CharField(
|
||||
max_length=128, verbose_name="路由地址", null=True, blank=True, help_text="路由地址"
|
||||
)
|
||||
component = models.CharField(
|
||||
max_length=128, verbose_name="组件地址", null=True, blank=True, help_text="组件地址"
|
||||
)
|
||||
component_name = models.CharField(
|
||||
max_length=50, verbose_name="组件名称", null=True, blank=True, help_text="组件名称"
|
||||
)
|
||||
status = models.BooleanField(
|
||||
default=True, blank=True, verbose_name="菜单状态", help_text="菜单状态"
|
||||
)
|
||||
cache = models.BooleanField(
|
||||
default=False, blank=True, verbose_name="是否页面缓存", help_text="是否页面缓存"
|
||||
)
|
||||
visible = models.BooleanField(
|
||||
default=True, blank=True, verbose_name="侧边栏中是否显示", help_text="侧边栏中是否显示"
|
||||
)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "system_menu"
|
||||
verbose_name = '菜单表'
|
||||
verbose_name = "菜单表"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ('sort',)
|
||||
ordering = ("sort",)
|
||||
|
||||
|
||||
class MenuButton(CoreModel):
|
||||
menu = models.ForeignKey(to="Menu", db_constraint=False, related_name="menuPermission", on_delete=models.CASCADE,
|
||||
verbose_name="关联菜单", help_text='关联菜单')
|
||||
menu = models.ForeignKey(
|
||||
to="Menu",
|
||||
db_constraint=False,
|
||||
related_name="menuPermission",
|
||||
on_delete=models.CASCADE,
|
||||
verbose_name="关联菜单",
|
||||
help_text="关联菜单",
|
||||
)
|
||||
name = models.CharField(max_length=64, verbose_name="名称", help_text="名称")
|
||||
value = models.CharField(max_length=64, verbose_name="权限值", help_text="权限值")
|
||||
api = models.CharField(max_length=200, verbose_name="接口地址", help_text="接口地址")
|
||||
|
@ -147,78 +247,121 @@ class MenuButton(CoreModel):
|
|||
(2, "PUT"),
|
||||
(3, "DELETE"),
|
||||
)
|
||||
method = models.IntegerField(default=0, verbose_name="接口请求方法", null=True, blank=True, help_text="接口请求方法")
|
||||
method = models.IntegerField(
|
||||
default=0, verbose_name="接口请求方法", null=True, blank=True, help_text="接口请求方法"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "system_menu_button"
|
||||
verbose_name = '菜单权限表'
|
||||
verbose_name = "菜单权限表"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ('-name',)
|
||||
ordering = ("-name",)
|
||||
|
||||
|
||||
class Dictionary(CoreModel):
|
||||
class Dictionary(MP_Node, CoreModel):
|
||||
TYPE_LIST = (
|
||||
(0, 'text'),
|
||||
(1, 'number'),
|
||||
(2, 'date'),
|
||||
(3, 'datetime'),
|
||||
(4, 'time'),
|
||||
(5, 'files'),
|
||||
(6, 'boolean'),
|
||||
(7, 'images'),
|
||||
(0, "text"),
|
||||
(1, "number"),
|
||||
(2, "date"),
|
||||
(3, "datetime"),
|
||||
(4, "time"),
|
||||
(5, "files"),
|
||||
(6, "boolean"),
|
||||
(7, "images"),
|
||||
)
|
||||
label = models.CharField(
|
||||
max_length=100, blank=True, null=True, verbose_name="字典名称", help_text="字典名称"
|
||||
)
|
||||
value = models.CharField(
|
||||
max_length=200, blank=True, null=True, verbose_name="字典编号", help_text="字典编号/实际值"
|
||||
)
|
||||
type = models.IntegerField(
|
||||
choices=TYPE_LIST, default=0, verbose_name="数据值类型", help_text="数据值类型"
|
||||
)
|
||||
color = models.CharField(
|
||||
max_length=20, blank=True, null=True, verbose_name="颜色", help_text="颜色"
|
||||
)
|
||||
is_value = models.BooleanField(
|
||||
default=False, verbose_name="是否为value值", help_text="是否为value值,用来做具体值存放"
|
||||
)
|
||||
label = models.CharField(max_length=100, blank=True, null=True, verbose_name="字典名称", help_text="字典名称")
|
||||
value = models.CharField(max_length=200, blank=True, null=True, verbose_name="字典编号", help_text="字典编号/实际值")
|
||||
parent = models.ForeignKey(to='self', related_name='sublist', db_constraint=False, on_delete=models.PROTECT,
|
||||
blank=True, null=True, verbose_name="父级", help_text="父级")
|
||||
type = models.IntegerField(choices=TYPE_LIST, default=0, verbose_name="数据值类型", help_text="数据值类型")
|
||||
color = models.CharField(max_length=20, blank=True, null=True, verbose_name="颜色", help_text="颜色")
|
||||
is_value = models.BooleanField(default=False, verbose_name="是否为value值", help_text="是否为value值,用来做具体值存放")
|
||||
status = models.BooleanField(default=True, verbose_name="状态", help_text="状态")
|
||||
sort = models.IntegerField(default=1, verbose_name="显示排序", null=True, blank=True, help_text="显示排序")
|
||||
remark = models.CharField(max_length=2000, blank=True, null=True, verbose_name="备注", help_text="备注")
|
||||
sort = models.IntegerField(
|
||||
default=1, verbose_name="显示排序", null=True, blank=True, help_text="显示排序"
|
||||
)
|
||||
remark = models.CharField(
|
||||
max_length=2000, blank=True, null=True, verbose_name="备注", help_text="备注"
|
||||
)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.label
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + 'system_dictionary'
|
||||
db_table = table_prefix + "system_dictionary"
|
||||
verbose_name = "字典表"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ('sort',)
|
||||
ordering = ("sort",)
|
||||
|
||||
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
|
||||
def save(
|
||||
self, force_insert=False, force_update=False, using=None, update_fields=None
|
||||
):
|
||||
super().save(force_insert, force_update, using, update_fields)
|
||||
dispatch.refresh_dictionary() # 有更新则刷新字典配置
|
||||
dispatch.refresh_dictionary() # 有更新则刷新字典配置
|
||||
|
||||
|
||||
class OperationLog(CoreModel):
|
||||
request_modular = models.CharField(max_length=64, verbose_name="请求模块", null=True, blank=True, help_text="请求模块")
|
||||
request_path = models.CharField(max_length=400, verbose_name="请求地址", null=True, blank=True, help_text="请求地址")
|
||||
request_body = models.TextField(verbose_name="请求参数", null=True, blank=True, help_text="请求参数")
|
||||
request_method = models.CharField(max_length=8, verbose_name="请求方式", null=True, blank=True, help_text="请求方式")
|
||||
request_msg = models.TextField(verbose_name="操作说明", null=True, blank=True, help_text="操作说明")
|
||||
request_ip = models.CharField(max_length=32, verbose_name="请求ip地址", null=True, blank=True, help_text="请求ip地址")
|
||||
request_browser = models.CharField(max_length=64, verbose_name="请求浏览器", null=True, blank=True, help_text="请求浏览器")
|
||||
response_code = models.CharField(max_length=32, verbose_name="响应状态码", null=True, blank=True, help_text="响应状态码")
|
||||
request_os = models.CharField(max_length=64, verbose_name="操作系统", null=True, blank=True, help_text="操作系统")
|
||||
json_result = models.TextField(verbose_name="返回信息", null=True, blank=True, help_text="返回信息")
|
||||
request_modular = models.CharField(
|
||||
max_length=64, verbose_name="请求模块", null=True, blank=True, help_text="请求模块"
|
||||
)
|
||||
request_path = models.CharField(
|
||||
max_length=400, verbose_name="请求地址", null=True, blank=True, help_text="请求地址"
|
||||
)
|
||||
request_body = models.TextField(
|
||||
verbose_name="请求参数", null=True, blank=True, help_text="请求参数"
|
||||
)
|
||||
request_method = models.CharField(
|
||||
max_length=8, verbose_name="请求方式", null=True, blank=True, help_text="请求方式"
|
||||
)
|
||||
request_msg = models.TextField(
|
||||
verbose_name="操作说明", null=True, blank=True, help_text="操作说明"
|
||||
)
|
||||
request_ip = models.CharField(
|
||||
max_length=32, verbose_name="请求ip地址", null=True, blank=True, help_text="请求ip地址"
|
||||
)
|
||||
request_browser = models.CharField(
|
||||
max_length=64, verbose_name="请求浏览器", null=True, blank=True, help_text="请求浏览器"
|
||||
)
|
||||
response_code = models.CharField(
|
||||
max_length=32, verbose_name="响应状态码", null=True, blank=True, help_text="响应状态码"
|
||||
)
|
||||
request_os = models.CharField(
|
||||
max_length=64, verbose_name="操作系统", null=True, blank=True, help_text="操作系统"
|
||||
)
|
||||
json_result = models.TextField(
|
||||
verbose_name="返回信息", null=True, blank=True, help_text="返回信息"
|
||||
)
|
||||
status = models.BooleanField(default=False, verbose_name="响应状态", help_text="响应状态")
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + 'system_operation_log'
|
||||
verbose_name = '操作日志'
|
||||
db_table = table_prefix + "system_operation_log"
|
||||
verbose_name = "操作日志"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ('-create_datetime',)
|
||||
ordering = ("-create_datetime",)
|
||||
|
||||
|
||||
def media_file_name(instance, filename):
|
||||
h = instance.md5sum
|
||||
basename, ext = os.path.splitext(filename)
|
||||
return os.path.join('files', h[0:1], h[1:2], h + ext.lower())
|
||||
return os.path.join("files", h[0:1], h[1:2], h + ext.lower())
|
||||
|
||||
|
||||
class FileList(CoreModel):
|
||||
name = models.CharField(max_length=50, null=True, blank=True, verbose_name="名称", help_text="名称")
|
||||
name = models.CharField(
|
||||
max_length=50, null=True, blank=True, verbose_name="名称", help_text="名称"
|
||||
)
|
||||
url = models.FileField(upload_to=media_file_name)
|
||||
md5sum = models.CharField(max_length=36, blank=True, verbose_name="文件md5", help_text="文件md5")
|
||||
md5sum = models.CharField(
|
||||
max_length=36, blank=True, verbose_name="文件md5", help_text="文件md5"
|
||||
)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.md5sum: # file is new
|
||||
|
@ -229,27 +372,39 @@ class FileList(CoreModel):
|
|||
super(FileList, self).save(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + 'system_file_list'
|
||||
verbose_name = '文件管理'
|
||||
db_table = table_prefix + "system_file_list"
|
||||
verbose_name = "文件管理"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ('-create_datetime',)
|
||||
ordering = ("-create_datetime",)
|
||||
|
||||
|
||||
class Area(CoreModel):
|
||||
name = models.CharField(max_length=100, verbose_name="名称", help_text="名称")
|
||||
code = models.CharField(max_length=20, verbose_name="地区编码", help_text="地区编码", unique=True, db_index=True)
|
||||
level = models.BigIntegerField(verbose_name="地区层级(1省份 2城市 3区县 4乡级)", help_text="地区层级(1省份 2城市 3区县 4乡级)")
|
||||
code = models.CharField(
|
||||
max_length=20, verbose_name="地区编码", help_text="地区编码", unique=True, db_index=True
|
||||
)
|
||||
level = models.BigIntegerField(
|
||||
verbose_name="地区层级(1省份 2城市 3区县 4乡级)", help_text="地区层级(1省份 2城市 3区县 4乡级)"
|
||||
)
|
||||
pinyin = models.CharField(max_length=255, verbose_name="拼音", help_text="拼音")
|
||||
initials = models.CharField(max_length=20, verbose_name="首字母", help_text="首字母")
|
||||
enable = models.BooleanField(default=True, verbose_name="是否启用", help_text="是否启用")
|
||||
pcode = models.ForeignKey(to='self', verbose_name='父地区编码', to_field="code", on_delete=models.CASCADE,
|
||||
db_constraint=False, null=True, blank=True, help_text="父地区编码")
|
||||
pcode = models.ForeignKey(
|
||||
to="self",
|
||||
verbose_name="父地区编码",
|
||||
to_field="code",
|
||||
on_delete=models.CASCADE,
|
||||
db_constraint=False,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="父地区编码",
|
||||
)
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "system_area"
|
||||
verbose_name = '地区表'
|
||||
verbose_name = "地区表"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ('code',)
|
||||
ordering = ("code",)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name}"
|
||||
|
@ -263,89 +418,150 @@ class ApiWhiteList(CoreModel):
|
|||
(2, "PUT"),
|
||||
(3, "DELETE"),
|
||||
)
|
||||
method = models.IntegerField(default=0, verbose_name="接口请求方法", null=True, blank=True, help_text="接口请求方法")
|
||||
enable_datasource = models.BooleanField(default=True, verbose_name="激活数据权限", help_text="激活数据权限", blank=True)
|
||||
method = models.IntegerField(
|
||||
default=0, verbose_name="接口请求方法", null=True, blank=True, help_text="接口请求方法"
|
||||
)
|
||||
enable_datasource = models.BooleanField(
|
||||
default=True, verbose_name="激活数据权限", help_text="激活数据权限", blank=True
|
||||
)
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "api_white_list"
|
||||
verbose_name = '接口白名单'
|
||||
verbose_name = "接口白名单"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ('-create_datetime',)
|
||||
ordering = ("-create_datetime",)
|
||||
|
||||
|
||||
class SystemConfig(CoreModel):
|
||||
parent = models.ForeignKey(to='self', verbose_name='父级', on_delete=models.CASCADE,
|
||||
db_constraint=False, null=True, blank=True, help_text="父级")
|
||||
class SystemConfig(AL_Node, CoreModel):
|
||||
parent = models.ForeignKey(
|
||||
to="self",
|
||||
verbose_name="父级",
|
||||
on_delete=models.CASCADE,
|
||||
db_constraint=False,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="父级",
|
||||
)
|
||||
title = models.CharField(max_length=50, verbose_name="标题", help_text="标题")
|
||||
key = models.CharField(max_length=20, verbose_name="键", help_text="键", db_index=True)
|
||||
value = models.JSONField(max_length=100, verbose_name="值", help_text="值", null=True, blank=True)
|
||||
key = models.CharField(
|
||||
max_length=20, verbose_name="键", help_text="键", db_index=True
|
||||
)
|
||||
value = models.JSONField(
|
||||
max_length=100, verbose_name="值", help_text="值", null=True, blank=True
|
||||
)
|
||||
sort = models.IntegerField(default=0, verbose_name="排序", help_text="排序", blank=True)
|
||||
status = models.BooleanField(default=True, verbose_name="启用状态", help_text="启用状态")
|
||||
data_options = models.JSONField(verbose_name="数据options", help_text="数据options", null=True, blank=True)
|
||||
FORM_ITEM_TYPE_LIST = (
|
||||
(0, 'text'),
|
||||
(1, 'datetime'),
|
||||
(2, 'date'),
|
||||
(3, 'textarea'),
|
||||
(4, 'select'),
|
||||
(5, 'checkbox'),
|
||||
(6, 'radio'),
|
||||
(7, 'img'),
|
||||
(8, 'file'),
|
||||
(9, 'switch'),
|
||||
(10, 'number'),
|
||||
(11, 'array'),
|
||||
(12, 'imgs'),
|
||||
(13, 'foreignkey'),
|
||||
(14, 'manytomany'),
|
||||
(15, 'time'),
|
||||
|
||||
data_options = models.JSONField(
|
||||
verbose_name="数据options", help_text="数据options", null=True, blank=True
|
||||
)
|
||||
FORM_ITEM_TYPE_LIST = (
|
||||
(0, "text"),
|
||||
(1, "datetime"),
|
||||
(2, "date"),
|
||||
(3, "textarea"),
|
||||
(4, "select"),
|
||||
(5, "checkbox"),
|
||||
(6, "radio"),
|
||||
(7, "img"),
|
||||
(8, "file"),
|
||||
(9, "switch"),
|
||||
(10, "number"),
|
||||
(11, "array"),
|
||||
(12, "imgs"),
|
||||
(13, "foreignkey"),
|
||||
(14, "manytomany"),
|
||||
(15, "time"),
|
||||
)
|
||||
form_item_type = models.IntegerField(
|
||||
choices=FORM_ITEM_TYPE_LIST,
|
||||
verbose_name="表单类型",
|
||||
help_text="表单类型",
|
||||
default=0,
|
||||
blank=True,
|
||||
)
|
||||
rule = models.JSONField(
|
||||
null=True, blank=True, verbose_name="校验规则", help_text="校验规则"
|
||||
)
|
||||
placeholder = models.CharField(
|
||||
max_length=50, null=True, blank=True, verbose_name="提示信息", help_text="提示信息"
|
||||
)
|
||||
form_item_type = models.IntegerField(choices=FORM_ITEM_TYPE_LIST, verbose_name="表单类型", help_text="表单类型", default=0,
|
||||
blank=True)
|
||||
rule = models.JSONField(null=True, blank=True, verbose_name="校验规则", help_text="校验规则")
|
||||
placeholder = models.CharField(max_length=50, null=True, blank=True, verbose_name="提示信息", help_text="提示信息")
|
||||
setting = models.JSONField(null=True, blank=True, verbose_name="配置", help_text="配置")
|
||||
|
||||
node_order_by = ["sort", "title", "key"]
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "system_config"
|
||||
verbose_name = '系统配置表'
|
||||
verbose_name = "系统配置表"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ('sort',)
|
||||
ordering = ("sort",)
|
||||
unique_together = (("key", "parent_id"),)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.title}"
|
||||
|
||||
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
|
||||
def save(
|
||||
self, force_insert=False, force_update=False, using=None, update_fields=None
|
||||
):
|
||||
super().save(force_insert, force_update, using, update_fields)
|
||||
dispatch.refresh_system_config() # 有更新则刷新系统配置
|
||||
dispatch.refresh_system_config() # 有更新则刷新系统配置
|
||||
|
||||
|
||||
class LoginLog(CoreModel):
|
||||
LOGIN_TYPE_CHOICES = (
|
||||
(1, '普通登录'),
|
||||
LOGIN_TYPE_CHOICES = ((1, "普通登录"),)
|
||||
username = models.CharField(
|
||||
max_length=32, verbose_name="登录用户名", null=True, blank=True, help_text="登录用户名"
|
||||
)
|
||||
ip = models.CharField(
|
||||
max_length=32, verbose_name="登录ip", null=True, blank=True, help_text="登录ip"
|
||||
)
|
||||
agent = models.TextField(
|
||||
verbose_name="agent信息", null=True, blank=True, help_text="agent信息"
|
||||
)
|
||||
browser = models.CharField(
|
||||
max_length=200, verbose_name="浏览器名", null=True, blank=True, help_text="浏览器名"
|
||||
)
|
||||
os = models.CharField(
|
||||
max_length=200, verbose_name="操作系统", null=True, blank=True, help_text="操作系统"
|
||||
)
|
||||
continent = models.CharField(
|
||||
max_length=50, verbose_name="州", null=True, blank=True, help_text="州"
|
||||
)
|
||||
country = models.CharField(
|
||||
max_length=50, verbose_name="国家", null=True, blank=True, help_text="国家"
|
||||
)
|
||||
province = models.CharField(
|
||||
max_length=50, verbose_name="省份", null=True, blank=True, help_text="省份"
|
||||
)
|
||||
city = models.CharField(
|
||||
max_length=50, verbose_name="城市", null=True, blank=True, help_text="城市"
|
||||
)
|
||||
district = models.CharField(
|
||||
max_length=50, verbose_name="县区", null=True, blank=True, help_text="县区"
|
||||
)
|
||||
isp = models.CharField(
|
||||
max_length=50, verbose_name="运营商", null=True, blank=True, help_text="运营商"
|
||||
)
|
||||
area_code = models.CharField(
|
||||
max_length=50, verbose_name="区域代码", null=True, blank=True, help_text="区域代码"
|
||||
)
|
||||
country_english = models.CharField(
|
||||
max_length=50, verbose_name="英文全称", null=True, blank=True, help_text="英文全称"
|
||||
)
|
||||
country_code = models.CharField(
|
||||
max_length=50, verbose_name="简称", null=True, blank=True, help_text="简称"
|
||||
)
|
||||
longitude = models.CharField(
|
||||
max_length=50, verbose_name="经度", null=True, blank=True, help_text="经度"
|
||||
)
|
||||
latitude = models.CharField(
|
||||
max_length=50, verbose_name="纬度", null=True, blank=True, help_text="纬度"
|
||||
)
|
||||
login_type = models.IntegerField(
|
||||
default=1, choices=LOGIN_TYPE_CHOICES, verbose_name="登录类型", help_text="登录类型"
|
||||
)
|
||||
username = models.CharField(max_length=32, verbose_name="登录用户名", null=True, blank=True, help_text="登录用户名")
|
||||
ip = models.CharField(max_length=32, verbose_name="登录ip", null=True, blank=True, help_text="登录ip")
|
||||
agent = models.TextField(verbose_name="agent信息", null=True, blank=True, help_text="agent信息")
|
||||
browser = models.CharField(max_length=200, verbose_name="浏览器名", null=True, blank=True, help_text="浏览器名")
|
||||
os = models.CharField(max_length=200, verbose_name="操作系统", null=True, blank=True, help_text="操作系统")
|
||||
continent = models.CharField(max_length=50, verbose_name="州", null=True, blank=True, help_text="州")
|
||||
country = models.CharField(max_length=50, verbose_name="国家", null=True, blank=True, help_text="国家")
|
||||
province = models.CharField(max_length=50, verbose_name="省份", null=True, blank=True, help_text="省份")
|
||||
city = models.CharField(max_length=50, verbose_name="城市", null=True, blank=True, help_text="城市")
|
||||
district = models.CharField(max_length=50, verbose_name="县区", null=True, blank=True, help_text="县区")
|
||||
isp = models.CharField(max_length=50, verbose_name="运营商", null=True, blank=True, help_text="运营商")
|
||||
area_code = models.CharField(max_length=50, verbose_name="区域代码", null=True, blank=True, help_text="区域代码")
|
||||
country_english = models.CharField(max_length=50, verbose_name="英文全称", null=True, blank=True, help_text="英文全称")
|
||||
country_code = models.CharField(max_length=50, verbose_name="简称", null=True, blank=True, help_text="简称")
|
||||
longitude = models.CharField(max_length=50, verbose_name="经度", null=True, blank=True, help_text="经度")
|
||||
latitude = models.CharField(max_length=50, verbose_name="纬度", null=True, blank=True, help_text="纬度")
|
||||
login_type = models.IntegerField(default=1, choices=LOGIN_TYPE_CHOICES, verbose_name="登录类型", help_text="登录类型")
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + 'system_login_log'
|
||||
verbose_name = '登录日志'
|
||||
db_table = table_prefix + "system_login_log"
|
||||
verbose_name = "登录日志"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ('-create_datetime',)
|
||||
ordering = ("-create_datetime",)
|
||||
|
|
|
@ -31,6 +31,7 @@ class DictionaryInitSerializer(CustomModelSerializer):
|
|||
"""
|
||||
初始化获取数信息(用于生成初始化json文件)
|
||||
"""
|
||||
|
||||
children = serializers.SerializerMethodField()
|
||||
|
||||
def get_children(self, obj: Dictionary):
|
||||
|
@ -43,29 +44,40 @@ class DictionaryInitSerializer(CustomModelSerializer):
|
|||
|
||||
def save(self, **kwargs):
|
||||
instance = super().save(**kwargs)
|
||||
children = self.initial_data.get('children')
|
||||
children = self.initial_data.get("children")
|
||||
# 菜单表
|
||||
if children:
|
||||
for data in children:
|
||||
data['parent'] = instance.id
|
||||
filter_data = {
|
||||
"value": data['value'],
|
||||
"parent": data['parent']
|
||||
}
|
||||
data["parent"] = instance.id
|
||||
filter_data = {"value": data["value"], "parent": data["parent"]}
|
||||
instance_obj = Dictionary.objects.filter(**filter_data).first()
|
||||
serializer = DictionaryInitSerializer(instance_obj, data=data, request=self.request)
|
||||
serializer = DictionaryInitSerializer(
|
||||
instance_obj, data=data, request=self.request
|
||||
)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
return instance
|
||||
|
||||
class Meta:
|
||||
model = Dictionary
|
||||
fields = ['label', 'value', 'parent', 'type', 'color', 'is_value', 'status', 'sort', 'remark', 'creator',
|
||||
'dept_belong_id', 'children']
|
||||
fields = [
|
||||
"label",
|
||||
"value",
|
||||
"parent",
|
||||
"type",
|
||||
"color",
|
||||
"is_value",
|
||||
"status",
|
||||
"sort",
|
||||
"remark",
|
||||
"creator",
|
||||
"dept_belong_id",
|
||||
"children",
|
||||
]
|
||||
read_only_fields = ["id"]
|
||||
extra_kwargs = {
|
||||
'creator': {'write_only': True},
|
||||
'dept_belong_id': {'write_only': True}
|
||||
"creator": {"write_only": True},
|
||||
"dept_belong_id": {"write_only": True},
|
||||
}
|
||||
|
||||
|
||||
|
@ -76,7 +88,7 @@ class DictionaryCreateUpdateSerializer(CustomModelSerializer):
|
|||
|
||||
class Meta:
|
||||
model = Dictionary
|
||||
fields = '__all__'
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class DictionaryViewSet(CustomModelViewSet):
|
||||
|
@ -88,30 +100,46 @@ class DictionaryViewSet(CustomModelViewSet):
|
|||
retrieve:单例
|
||||
destroy:删除
|
||||
"""
|
||||
|
||||
queryset = Dictionary.objects.all()
|
||||
serializer_class = DictionarySerializer
|
||||
extra_filter_backends = []
|
||||
search_fields = ['label']
|
||||
search_fields = ["label"]
|
||||
|
||||
def get_queryset(self):
|
||||
parent_id = self.request.query_params.get("parent", None)
|
||||
if parent_id:
|
||||
return self.queryset.get(id=parent_id).get_children()
|
||||
return super().get_queryset()
|
||||
|
||||
|
||||
class InitDictionaryViewSet(APIView):
|
||||
"""
|
||||
获取初始化配置
|
||||
"""
|
||||
|
||||
authentication_classes = []
|
||||
permission_classes = []
|
||||
queryset = Dictionary.objects.all()
|
||||
|
||||
def get(self, request):
|
||||
dictionary_key = self.request.query_params.get('dictionary_key')
|
||||
dictionary_key = self.request.query_params.get("dictionary_key")
|
||||
if dictionary_key:
|
||||
if dictionary_key == 'all':
|
||||
if dictionary_key == "all":
|
||||
data = [ele for ele in dispatch.get_dictionary_config().values()]
|
||||
if not data:
|
||||
dispatch.refresh_dictionary()
|
||||
data = [ele for ele in dispatch.get_dictionary_config().values()]
|
||||
else:
|
||||
data = self.queryset.filter(parent__value=dictionary_key, status=True).values('label', 'value', 'type',
|
||||
'color')
|
||||
# data = self.queryset.filter(
|
||||
# parent__value=dictionary_key, status=True
|
||||
# ).values("label", "value", "type", "color")
|
||||
data = (
|
||||
Dictionary.objects.get(value=dictionary_key)
|
||||
.get_children()
|
||||
.filter(status=True)
|
||||
.values("label", "value", "type", "color")
|
||||
)
|
||||
print(data)
|
||||
return SuccessResponse(data=data, msg="获取成功")
|
||||
return SuccessResponse(data=[], msg="获取成功")
|
||||
|
|
|
@ -20,10 +20,19 @@ class MenuSerializer(CustomModelSerializer):
|
|||
"""
|
||||
菜单表的简单序列化器
|
||||
"""
|
||||
|
||||
parent = serializers.SerializerMethodField(read_only=True)
|
||||
menuPermission = serializers.SerializerMethodField(read_only=True)
|
||||
|
||||
def get_parent(self, instance):
|
||||
return instance.get_parent().id if instance.get_parent() else None
|
||||
|
||||
def get_menuPermission(self, instance):
|
||||
queryset = MenuButton.objects.filter(menu=instance.id).order_by('-name').values_list('name', flat=True)
|
||||
queryset = (
|
||||
MenuButton.objects.filter(menu=instance.id)
|
||||
.order_by("-name")
|
||||
.values_list("name", flat=True)
|
||||
)
|
||||
if queryset:
|
||||
return queryset
|
||||
else:
|
||||
|
@ -39,6 +48,7 @@ class MenuCreateSerializer(CustomModelSerializer):
|
|||
"""
|
||||
菜单表的创建序列化器
|
||||
"""
|
||||
|
||||
name = serializers.CharField(required=False)
|
||||
|
||||
class Meta:
|
||||
|
@ -51,6 +61,7 @@ class MenuInitSerializer(CustomModelSerializer):
|
|||
"""
|
||||
递归深度获取数信息(用于生成初始化json文件)
|
||||
"""
|
||||
|
||||
name = serializers.CharField(required=False)
|
||||
children = serializers.SerializerMethodField()
|
||||
menu_button = serializers.SerializerMethodField()
|
||||
|
@ -65,70 +76,97 @@ class MenuInitSerializer(CustomModelSerializer):
|
|||
|
||||
def get_menu_button(self, obj: Menu):
|
||||
data = []
|
||||
instance = MenuButton.objects.filter(menu_id=obj.id).order_by('method')
|
||||
instance = MenuButton.objects.filter(menu_id=obj.id).order_by("method")
|
||||
if instance:
|
||||
data = list(instance.values('name', 'value', 'api', 'method'))
|
||||
data = list(instance.values("name", "value", "api", "method"))
|
||||
return data
|
||||
|
||||
def save(self, **kwargs):
|
||||
instance = super().save(**kwargs)
|
||||
children = self.initial_data.get('children')
|
||||
menu_button = self.initial_data.get('menu_button')
|
||||
children = self.initial_data.get("children")
|
||||
menu_button = self.initial_data.get("menu_button")
|
||||
# 菜单表
|
||||
if children:
|
||||
for menu_data in children:
|
||||
menu_data['parent'] = instance.id
|
||||
menu_data["parent"] = instance.id
|
||||
filter_data = {
|
||||
"name": menu_data['name'],
|
||||
"web_path": menu_data['web_path'],
|
||||
"component": menu_data['component'],
|
||||
"component_name": menu_data['component_name'],
|
||||
"name": menu_data["name"],
|
||||
"web_path": menu_data["web_path"],
|
||||
"component": menu_data["component"],
|
||||
"component_name": menu_data["component_name"],
|
||||
}
|
||||
instance_obj = Menu.objects.filter(**filter_data).first()
|
||||
serializer = MenuInitSerializer(instance_obj, data=menu_data, request=self.request)
|
||||
serializer = MenuInitSerializer(
|
||||
instance_obj, data=menu_data, request=self.request
|
||||
)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
# 菜单按钮
|
||||
if menu_button:
|
||||
for menu_button_data in menu_button:
|
||||
menu_button_data['menu'] = instance.id
|
||||
menu_button_data["menu"] = instance.id
|
||||
filter_data = {
|
||||
"menu": menu_button_data['menu'],
|
||||
"value": menu_button_data['value']
|
||||
"menu": menu_button_data["menu"],
|
||||
"value": menu_button_data["value"],
|
||||
}
|
||||
instance_obj = MenuButton.objects.filter(**filter_data).first()
|
||||
serializer = MenuButtonSerializer(instance_obj, data=menu_button_data, request=self.request)
|
||||
serializer = MenuButtonSerializer(
|
||||
instance_obj, data=menu_button_data, request=self.request
|
||||
)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
return instance
|
||||
|
||||
class Meta:
|
||||
model = Menu
|
||||
fields = ['name', 'icon', 'sort', 'is_link', 'is_catalog', 'web_path', 'component', 'component_name', 'status',
|
||||
'cache', 'visible', 'parent', 'children', 'menu_button', 'creator', 'dept_belong_id']
|
||||
fields = [
|
||||
"name",
|
||||
"icon",
|
||||
"sort",
|
||||
"is_link",
|
||||
"is_catalog",
|
||||
"web_path",
|
||||
"component",
|
||||
"component_name",
|
||||
"status",
|
||||
"cache",
|
||||
"visible",
|
||||
"parent",
|
||||
"children",
|
||||
"menu_button",
|
||||
"creator",
|
||||
"dept_belong_id",
|
||||
]
|
||||
extra_kwargs = {
|
||||
'creator': {'write_only': True},
|
||||
'dept_belong_id': {'write_only': True}
|
||||
"creator": {"write_only": True},
|
||||
"dept_belong_id": {"write_only": True},
|
||||
}
|
||||
read_only_fields = ['id', 'children']
|
||||
read_only_fields = ["id", "children"]
|
||||
|
||||
|
||||
class WebRouterSerializer(CustomModelSerializer):
|
||||
"""
|
||||
前端菜单路由的简单序列化器
|
||||
"""
|
||||
|
||||
path = serializers.CharField(source="web_path")
|
||||
title = serializers.CharField(source="name")
|
||||
parent = serializers.SerializerMethodField(read_only=True)
|
||||
menuPermission = serializers.SerializerMethodField(read_only=True)
|
||||
|
||||
def get_parent(self, instance):
|
||||
return instance.get_parent().id if instance.get_parent() else None
|
||||
|
||||
def get_menuPermission(self, instance):
|
||||
# 判断是否是超级管理员
|
||||
if self.request.user.is_superuser:
|
||||
return MenuButton.objects.values_list('value', flat=True)
|
||||
return MenuButton.objects.values_list("value", flat=True)
|
||||
else:
|
||||
# 根据当前角色获取权限按钮id集合
|
||||
permissionIds = self.request.user.role.values_list('permission', flat=True)
|
||||
queryset = MenuButton.objects.filter(id__in=permissionIds, menu=instance.id).values_list('value', flat=True)
|
||||
permissionIds = self.request.user.role.values_list("permission", flat=True)
|
||||
queryset = MenuButton.objects.filter(
|
||||
id__in=permissionIds, menu=instance.id
|
||||
).values_list("value", flat=True)
|
||||
if queryset:
|
||||
return queryset
|
||||
else:
|
||||
|
@ -149,21 +187,29 @@ class MenuViewSet(CustomModelViewSet):
|
|||
retrieve:单例
|
||||
destroy:删除
|
||||
"""
|
||||
|
||||
queryset = Menu.objects.all()
|
||||
serializer_class = MenuSerializer
|
||||
create_serializer_class = MenuCreateSerializer
|
||||
update_serializer_class = MenuCreateSerializer
|
||||
search_fields = ['name', 'status']
|
||||
filter_fields = ['parent', 'name', 'status', 'is_link', 'visible', 'cache', 'is_catalog']
|
||||
search_fields = ["name", "status"]
|
||||
filter_fields = [
|
||||
"name",
|
||||
"status",
|
||||
"is_link",
|
||||
"visible",
|
||||
"cache",
|
||||
"is_catalog",
|
||||
]
|
||||
extra_filter_backends = []
|
||||
|
||||
@action(methods=['GET'], detail=True, permission_classes=[])
|
||||
@action(methods=["GET"], detail=True, permission_classes=[])
|
||||
def web_router(self, request):
|
||||
"""用于前端获取当前角色的路由"""
|
||||
user = request.user
|
||||
queryset = self.queryset.filter(status=1)
|
||||
if not user.is_superuser:
|
||||
menuIds = user.role.values_list('menu__id', flat=True)
|
||||
menuIds = user.role.values_list("menu__id", flat=True)
|
||||
queryset = Menu.objects.filter(id__in=menuIds, status=1)
|
||||
serializer = WebRouterSerializer(queryset, many=True, request=request)
|
||||
data = serializer.data
|
||||
|
|
|
@ -7,12 +7,14 @@ from rest_framework import request
|
|||
|
||||
from application import settings
|
||||
from dvadmin.system.models import Users
|
||||
from treebeard.mp_tree import MP_Node
|
||||
|
||||
|
||||
class CoreInitialize:
|
||||
"""
|
||||
使用方法:继承此类,重写 run方法,在 run 中调用 save 进行数据初始化
|
||||
"""
|
||||
|
||||
creator_id = None
|
||||
reset = False
|
||||
request = request
|
||||
|
@ -25,13 +27,16 @@ class CoreInitialize:
|
|||
"""
|
||||
self.reset = reset or self.reset
|
||||
self.creator_id = creator_id or self.creator_id
|
||||
self.app = app or ''
|
||||
self.request.user = Users.objects.order_by('create_datetime').first()
|
||||
self.app = app or ""
|
||||
self.request.user = Users.objects.order_by("create_datetime").first()
|
||||
|
||||
def init_base(self, Serializer, unique_fields=None):
|
||||
model = Serializer.Meta.model
|
||||
path_file = os.path.join(apps.get_app_config(self.app.split('.')[-1]).path, 'fixtures',
|
||||
f'init_{Serializer.Meta.model._meta.model_name}.json')
|
||||
path_file = os.path.join(
|
||||
apps.get_app_config(self.app.split(".")[-1]).path,
|
||||
"fixtures",
|
||||
f"init_{Serializer.Meta.model._meta.model_name}.json",
|
||||
)
|
||||
if not os.path.isfile(path_file):
|
||||
return
|
||||
with open(path_file) as f:
|
||||
|
@ -44,7 +49,7 @@ class CoreInitialize:
|
|||
filter_data[field] = data[field]
|
||||
else:
|
||||
for key, value in data.items():
|
||||
if isinstance(value, list) or value == None or value == '':
|
||||
if isinstance(value, list) or value == None or value == "":
|
||||
continue
|
||||
filter_data[key] = value
|
||||
instance = model.objects.filter(**filter_data).first()
|
||||
|
@ -62,26 +67,33 @@ class CoreInitialize:
|
|||
settings.INITIALIZE_RESET_LIST.append(obj)
|
||||
except Exception:
|
||||
pass
|
||||
for ele in data:
|
||||
m2m_dict = {}
|
||||
new_data = {}
|
||||
for key, value in ele.items():
|
||||
# 判断传的 value 为 list 的多对多进行抽离,使用set 进行更新
|
||||
if isinstance(value, list) and value and isinstance(value[0], int):
|
||||
m2m_dict[key] = value
|
||||
else:
|
||||
new_data[key] = value
|
||||
object, _ = obj.objects.get_or_create(id=ele.get("id"), defaults=new_data)
|
||||
for key, m2m in m2m_dict.items():
|
||||
m2m = list(set(m2m))
|
||||
if m2m and len(m2m) > 0 and m2m[0]:
|
||||
exec(f"""
|
||||
if MP_Node in obj.__mro__:
|
||||
obj.load_bulk(data, None, True)
|
||||
else:
|
||||
for ele in data:
|
||||
m2m_dict = {}
|
||||
new_data = {}
|
||||
for key, value in ele.items():
|
||||
# 判断传的 value 为 list 的多对多进行抽离,使用set 进行更新
|
||||
if isinstance(value, list) and value and isinstance(value[0], int):
|
||||
m2m_dict[key] = value
|
||||
else:
|
||||
new_data[key] = value
|
||||
object, _ = obj.objects.get_or_create(
|
||||
id=ele.get("id"), defaults=new_data
|
||||
)
|
||||
for key, m2m in m2m_dict.items():
|
||||
m2m = list(set(m2m))
|
||||
if m2m and len(m2m) > 0 and m2m[0]:
|
||||
exec(
|
||||
f"""
|
||||
if object.{key}:
|
||||
values_list = object.{key}.all().values_list('id', flat=True)
|
||||
values_list = list(set(list(values_list) + {m2m}))
|
||||
object.{key}.set(values_list)
|
||||
""")
|
||||
"""
|
||||
)
|
||||
print(f"初始化完成[{obj._meta.label} => {name}]")
|
||||
|
||||
def run(self):
|
||||
raise NotImplementedError('.run() must be overridden')
|
||||
raise NotImplementedError(".run() must be overridden")
|
||||
|
|
|
@ -23,6 +23,10 @@ class CustomModelSerializer(DynamicFieldsMixin, ModelSerializer):
|
|||
(1)self.request能获取到rest_framework.request.Request对象
|
||||
"""
|
||||
|
||||
# 放空treebeard.mp_tree.MP_Node的继承字段
|
||||
path = serializers.CharField(required=False)
|
||||
depth = serializers.IntegerField(required=False)
|
||||
|
||||
# 修改人的审计字段名称, 默认modifier, 继承使用时可自定义覆盖
|
||||
modifier_field_id = "modifier"
|
||||
modifier_name = serializers.SerializerMethodField(read_only=True)
|
||||
|
|
|
@ -14,12 +14,19 @@ from rest_framework.decorators import action
|
|||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from dvadmin.utils.filters import DataLevelPermissionsFilter
|
||||
from dvadmin.utils.import_export_mixin import ExportSerializerMixin, ImportSerializerMixin
|
||||
from dvadmin.utils.import_export_mixin import (
|
||||
ExportSerializerMixin,
|
||||
ImportSerializerMixin,
|
||||
)
|
||||
from dvadmin.utils.json_response import SuccessResponse, ErrorResponse, DetailResponse
|
||||
from dvadmin.utils.permission import CustomPermission
|
||||
from django_restql.mixins import QueryArgumentsMixin
|
||||
from treebeard.models import Node
|
||||
|
||||
class CustomModelViewSet(ModelViewSet,ImportSerializerMixin,ExportSerializerMixin,QueryArgumentsMixin):
|
||||
|
||||
class CustomModelViewSet(
|
||||
ModelViewSet, ImportSerializerMixin, ExportSerializerMixin, QueryArgumentsMixin
|
||||
):
|
||||
"""
|
||||
自定义的ModelViewSet:
|
||||
统一标准的返回格式;新增,查询,修改可使用不同序列化器
|
||||
|
@ -29,11 +36,12 @@ class CustomModelViewSet(ModelViewSet,ImportSerializerMixin,ExportSerializerMixi
|
|||
(4)import_field_dict={} 导入时的字段字典 {model值: model的label}
|
||||
(5)export_field_label = [] 导出时的字段
|
||||
"""
|
||||
|
||||
values_queryset = None
|
||||
ordering_fields = '__all__'
|
||||
ordering_fields = "__all__"
|
||||
create_serializer_class = None
|
||||
update_serializer_class = None
|
||||
filter_fields = '__all__'
|
||||
filter_fields = "__all__"
|
||||
search_fields = ()
|
||||
extra_filter_backends = [DataLevelPermissionsFilter]
|
||||
permission_classes = [CustomPermission]
|
||||
|
@ -41,12 +49,14 @@ class CustomModelViewSet(ModelViewSet,ImportSerializerMixin,ExportSerializerMixi
|
|||
export_field_label = []
|
||||
|
||||
def filter_queryset(self, queryset):
|
||||
for backend in set(set(self.filter_backends) | set(self.extra_filter_backends or [])):
|
||||
for backend in set(
|
||||
set(self.filter_backends) | set(self.extra_filter_backends or [])
|
||||
):
|
||||
queryset = backend().filter_queryset(self.request, queryset, self)
|
||||
return queryset
|
||||
|
||||
def get_queryset(self):
|
||||
if getattr(self, 'values_queryset', None):
|
||||
if getattr(self, "values_queryset", None):
|
||||
return self.values_queryset
|
||||
return super().get_queryset()
|
||||
|
||||
|
@ -60,6 +70,15 @@ class CustomModelViewSet(ModelViewSet,ImportSerializerMixin,ExportSerializerMixi
|
|||
def create(self, request, *args, **kwargs):
|
||||
serializer = self.get_serializer(data=request.data, request=request)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
if Node in self.queryset.model.__mro__:
|
||||
parent_id = request.data.get("parent")
|
||||
data = serializer.validated_data
|
||||
if parent_id is None:
|
||||
self.queryset.model.add_root(**data)
|
||||
else:
|
||||
parent = self.queryset.model.objects.filter(pk=parent_id).first()
|
||||
parent.add_child(**data)
|
||||
return DetailResponse(data=data, msg="新增成功")
|
||||
self.perform_create(serializer)
|
||||
return DetailResponse(data=serializer.data, msg="新增成功")
|
||||
|
||||
|
@ -78,13 +97,15 @@ class CustomModelViewSet(ModelViewSet,ImportSerializerMixin,ExportSerializerMixi
|
|||
return DetailResponse(data=serializer.data, msg="获取成功")
|
||||
|
||||
def update(self, request, *args, **kwargs):
|
||||
partial = kwargs.pop('partial', False)
|
||||
partial = kwargs.pop("partial", False)
|
||||
instance = self.get_object()
|
||||
serializer = self.get_serializer(instance, data=request.data, request=request, partial=partial)
|
||||
serializer = self.get_serializer(
|
||||
instance, data=request.data, request=request, partial=partial
|
||||
)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
self.perform_update(serializer)
|
||||
|
||||
if getattr(instance, '_prefetched_objects_cache', None):
|
||||
if getattr(instance, "_prefetched_objects_cache", None):
|
||||
# If 'prefetch_related' has been applied to a queryset, we need to
|
||||
# forcibly invalidate the prefetch cache on the instance.
|
||||
instance._prefetched_objects_cache = {}
|
||||
|
@ -95,17 +116,20 @@ class CustomModelViewSet(ModelViewSet,ImportSerializerMixin,ExportSerializerMixi
|
|||
self.perform_destroy(instance)
|
||||
return DetailResponse(data=[], msg="删除成功")
|
||||
|
||||
keys = openapi.Schema(
|
||||
description="主键列表", type=openapi.TYPE_ARRAY, items=openapi.TYPE_STRING
|
||||
)
|
||||
|
||||
keys = openapi.Schema(description='主键列表',type=openapi.TYPE_ARRAY,items=openapi.TYPE_STRING)
|
||||
@swagger_auto_schema(request_body=openapi.Schema(
|
||||
type=openapi.TYPE_OBJECT,
|
||||
required=['keys'],
|
||||
properties={'keys': keys}
|
||||
), operation_summary='批量删除')
|
||||
@action(methods=['delete'],detail=False)
|
||||
def multiple_delete(self,request,*args,**kwargs):
|
||||
@swagger_auto_schema(
|
||||
request_body=openapi.Schema(
|
||||
type=openapi.TYPE_OBJECT, required=["keys"], properties={"keys": keys}
|
||||
),
|
||||
operation_summary="批量删除",
|
||||
)
|
||||
@action(methods=["delete"], detail=False)
|
||||
def multiple_delete(self, request, *args, **kwargs):
|
||||
request_data = request.data
|
||||
keys = request_data.get('keys',None)
|
||||
keys = request_data.get("keys", None)
|
||||
if keys:
|
||||
self.get_queryset().filter(id__in=keys).delete()
|
||||
return SuccessResponse(data=[], msg="删除成功")
|
||||
|
|
|
@ -41,3 +41,4 @@ urllib3==1.26.6
|
|||
user-agents==2.2.0
|
||||
whitenoise==5.3.0
|
||||
openpyxl==3.0.9
|
||||
django-treebeard>=4.5.1
|
|
@ -379,7 +379,7 @@ export const crudOptions = (vm) => {
|
|||
search: {
|
||||
disabled: false
|
||||
},
|
||||
width: 50,
|
||||
width: 60,
|
||||
type: 'radio',
|
||||
dict: {
|
||||
data: vm.dictionary('button_whether_bool')
|
||||
|
|
824
web/yarn.lock
824
web/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue