This commit is contained in:
sheng
2023-07-25 15:25:57 +08:00
parent 8f57a240db
commit 7ccbcebe77
373 changed files with 41578 additions and 0 deletions

View File

View File

@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View File

@@ -0,0 +1,6 @@
from django.apps import AppConfig
class SystemConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'dvadmin.system'

View File

@@ -0,0 +1,345 @@
# -*- coding: utf-8 -*-
import os
from rest_framework import serializers
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
import django
django.setup()
from dvadmin.system.models import Role, Dept, Users, Menu, MenuButton, ApiWhiteList, Dictionary, SystemConfig, \
RoleMenuPermission, RoleMenuButtonPermission
from dvadmin.utils.serializers import CustomModelSerializer
class UsersInitSerializer(CustomModelSerializer):
"""
初始化获取数信息(用于生成初始化json文件)
"""
def save(self, **kwargs):
instance = super().save(**kwargs)
role_key = self.initial_data.get('role_key', [])
role_ids = Role.objects.filter(key__in=role_key).values_list('id', flat=True)
instance.role.set(role_ids)
dept_key = self.initial_data.get('dept_key', None)
dept_id = Dept.objects.filter(key=dept_key).first()
instance.dept = dept_id
instance.save()
return instance
class Meta:
model = Users
fields = ["username", "email", 'mobile', 'avatar', "name", 'gender', 'user_type', "dept", 'user_type',
'first_name', 'last_name', 'email', 'is_staff', 'is_active', 'creator', 'dept_belong_id',
'password', 'last_login', 'is_superuser']
read_only_fields = ['id']
extra_kwargs = {
'creator': {'write_only': True},
'dept_belong_id': {'write_only': True}
}
class MenuButtonInitSerializer(CustomModelSerializer):
"""
初始化菜单按钮-序列化器
"""
class Meta:
model = MenuButton
fields = ['id', 'name', 'value', 'api', 'method', 'menu']
read_only_fields = ["id"]
class MenuInitSerializer(CustomModelSerializer):
"""
递归深度获取数信息(用于生成初始化json文件)
"""
name = serializers.CharField(required=False)
children = serializers.SerializerMethodField()
menu_button = serializers.SerializerMethodField()
def get_children(self, obj: Menu):
data = []
instance = Menu.objects.filter(parent_id=obj.id)
if instance:
serializer = MenuInitSerializer(instance=instance, many=True)
data = serializer.data
return data
def get_menu_button(self, obj: Menu):
data = []
instance = obj.menuPermission.order_by('method')
if instance:
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')
# 菜单表
if children:
for menu_data in children:
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'],
}
instance_obj = Menu.objects.filter(**filter_data).first()
if instance_obj and not self.initial_data.get('reset'):
continue
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
filter_data = {
"menu": menu_button_data['menu'],
"value": menu_button_data['value']
}
instance_obj = MenuButton.objects.filter(**filter_data).first()
serializer = MenuButtonInitSerializer(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']
extra_kwargs = {
'creator': {'write_only': True},
'dept_belong_id': {'write_only': True}
}
read_only_fields = ['id', 'children']
class RoleInitSerializer(CustomModelSerializer):
"""
初始化获取数信息(用于生成初始化json文件)
"""
class Meta:
model = Role
fields = ['name', 'key', 'sort', 'status', 'admin',
'creator', 'dept_belong_id']
read_only_fields = ["id"]
extra_kwargs = {
'creator': {'write_only': True},
'dept_belong_id': {'write_only': True}
}
class RoleMenuInitSerializer(CustomModelSerializer):
"""
初始化角色菜单(用于生成初始化json文件)
"""
role_key = serializers.CharField(max_length=100,required=True)
menu_component_name = serializers.CharField(max_length=100,required=True)
def create(self, validated_data):
init_data = self.initial_data
validated_data.pop('menu_component_name')
validated_data.pop('role_key')
role_id = Role.objects.filter(key=init_data['role_key']).first()
menu_id = Menu.objects.filter(component_name=init_data['menu_component_name']).first()
validated_data['role'] = role_id
validated_data['menu'] = menu_id
return super().create(validated_data)
class Meta:
model = RoleMenuPermission
fields = ['role_key','menu_component_name','creator', 'dept_belong_id']
read_only_fields = ["id"]
extra_kwargs = {
'role': {'required': False},
'menu': {'required': False},
'creator': {'write_only': True},
'dept_belong_id': {'write_only': True}
}
class RoleMenuButtonInitSerializer(CustomModelSerializer):
"""
初始化角色菜单按钮(用于生成初始化json文件)
"""
role_key = serializers.CharField(max_length=100,required=True)
menu_button_value = serializers.CharField(max_length=100,required=True)
data_range = serializers.CharField(max_length=100, required=False)
def create(self, validated_data):
init_data = self.initial_data
validated_data.pop('menu_button_value')
validated_data.pop('role_key')
role_id = Role.objects.filter(key=init_data['role_key']).first()
menu_button_id = MenuButton.objects.filter(value=init_data['menu_button_value']).first()
validated_data['role'] = role_id
validated_data['menu_button'] = menu_button_id
instance = super().create(validated_data)
instance.dept.set([])
return instance
class Meta:
model = RoleMenuButtonPermission
fields = ['role_key','menu_button_value','data_range','dept','creator', 'dept_belong_id']
read_only_fields = ["id"]
extra_kwargs = {
'role': {'required': False},
'menu': {'required': False},
'creator': {'write_only': True},
'dept_belong_id': {'write_only': True}
}
class ApiWhiteListInitSerializer(CustomModelSerializer):
"""
初始化获取数信息(用于生成初始化json文件)
"""
class Meta:
model = ApiWhiteList
fields = ['url', 'method', 'enable_datasource', 'creator', 'dept_belong_id']
read_only_fields = ["id"]
extra_kwargs = {
'creator': {'write_only': True},
'dept_belong_id': {'write_only': True}
}
class DeptInitSerializer(CustomModelSerializer):
"""
递归深度获取数信息(用于生成初始化json文件)
"""
children = serializers.SerializerMethodField()
def get_children(self, obj: Dept):
data = []
instance = Dept.objects.filter(parent_id=obj.id)
if instance:
serializer = DeptInitSerializer(instance=instance, many=True)
data = serializer.data
return data
def save(self, **kwargs):
instance = super().save(**kwargs)
children = self.initial_data.get('children')
if children:
for menu_data in children:
menu_data['parent'] = instance.id
filter_data = {
"name": menu_data['name'],
"parent": menu_data['parent'],
"key": menu_data['key']
}
instance_obj = Dept.objects.filter(**filter_data).first()
if instance_obj and not self.initial_data.get('reset'):
continue
serializer = DeptInitSerializer(instance_obj, data=menu_data, request=self.request)
serializer.is_valid(raise_exception=True)
serializer.save()
return instance
class Meta:
model = Dept
fields = ['name', 'sort', 'owner', 'phone', 'email', 'status', 'parent', 'creator', 'dept_belong_id',
'children', 'key']
extra_kwargs = {
'creator': {'write_only': True},
'dept_belong_id': {'write_only': True}
}
read_only_fields = ['id', 'children']
class DictionaryInitSerializer(CustomModelSerializer):
"""
初始化获取数信息(用于生成初始化json文件)
"""
children = serializers.SerializerMethodField()
def get_children(self, obj: Dictionary):
data = []
instance = Dictionary.objects.filter(parent_id=obj.id)
if instance:
serializer = DictionaryInitSerializer(instance=instance, many=True)
data = serializer.data
return data
def save(self, **kwargs):
instance = super().save(**kwargs)
children = self.initial_data.get('children')
# 菜单表
if children:
for data in children:
data['parent'] = instance.id
filter_data = {
"value": data['value'],
"parent": data['parent']
}
instance_obj = Dictionary.objects.filter(**filter_data).first()
if instance_obj and not self.initial_data.get('reset'):
continue
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']
read_only_fields = ["id"]
extra_kwargs = {
'creator': {'write_only': True},
'dept_belong_id': {'write_only': True}
}
class SystemConfigInitSerializer(CustomModelSerializer):
"""
初始化获取数信息(用于生成初始化json文件)
"""
children = serializers.SerializerMethodField()
def get_children(self, obj: SystemConfig):
data = []
instance = SystemConfig.objects.filter(parent_id=obj.id)
if instance:
serializer = SystemConfigInitSerializer(instance=instance, many=True)
data = serializer.data
return data
def save(self, **kwargs):
instance = super().save(**kwargs)
children = self.initial_data.get('children')
# 菜单表
if children:
for data in children:
data['parent'] = instance.id
filter_data = {
"key": data['key'],
"parent": data['parent']
}
instance_obj = SystemConfig.objects.filter(**filter_data).first()
if instance_obj and not self.initial_data.get('reset'):
continue
serializer = SystemConfigInitSerializer(instance_obj, data=data, request=self.request)
serializer.is_valid(raise_exception=True)
serializer.save()
return instance
class Meta:
model = SystemConfig
fields = ['parent', 'title', 'key', 'value', 'sort', 'status', 'data_options', 'form_item_type', 'rule',
'placeholder', 'setting', 'creator', 'dept_belong_id', 'children']
read_only_fields = ["id"]
extra_kwargs = {
'creator': {'write_only': True},
'dept_belong_id': {'write_only': True}
}

View File

@@ -0,0 +1,7 @@
[
{
"url": "/api/system/dept_lazy_tree/",
"method": 0,
"enable_datasource": true
}
]

View File

@@ -0,0 +1,36 @@
[
{
"name": "DVAdmin团队",
"key": "dvadmin",
"sort": 1,
"owner": "",
"phone": "",
"email": "",
"status": true,
"parent": null,
"children": [
{
"name": "运营部",
"key": "",
"sort": 2,
"owner": "",
"phone": "",
"email": "",
"status": true,
"parent": 1,
"children": []
},
{
"name": "技术部",
"key": "technology",
"sort": 1,
"owner": "",
"phone": "",
"email": "",
"status": true,
"parent": 3,
"children": []
}
]
}
]

View File

@@ -0,0 +1,550 @@
[
{
"label": "启用/禁用-布尔值",
"value": "button_status_bool",
"parent": null,
"type": 0,
"color": null,
"is_value": false,
"status": true,
"sort": 1,
"remark": null,
"children": [
{
"label": "启用",
"value": "true",
"parent": 1,
"type": 6,
"color": "success",
"is_value": true,
"status": true,
"sort": 1,
"remark": null,
"children": []
},
{
"label": "禁用",
"value": "false",
"parent": 1,
"type": 6,
"color": "danger",
"is_value": true,
"status": true,
"sort": 2,
"remark": null,
"children": []
}
]
},
{
"label": "系统按钮",
"value": "system_button",
"parent": null,
"type": 0,
"color": null,
"is_value": false,
"status": true,
"sort": 2,
"remark": null,
"children": [
{
"label": "新增",
"value": "Create",
"parent": 4,
"type": 0,
"color": "success",
"is_value": true,
"status": true,
"sort": 1,
"remark": null,
"children": []
},
{
"label": "编辑",
"value": "Update",
"parent": 4,
"type": 0,
"color": "primary",
"is_value": true,
"status": true,
"sort": 2,
"remark": null,
"children": []
},
{
"label": "删除",
"value": "Delete",
"parent": 4,
"type": 0,
"color": "danger",
"is_value": true,
"status": true,
"sort": 3,
"remark": null,
"children": []
},
{
"label": "详情",
"value": "Retrieve",
"parent": 4,
"type": 0,
"color": "info",
"is_value": true,
"status": true,
"sort": 4,
"remark": null,
"children": []
},
{
"label": "查询",
"value": "Search",
"parent": 4,
"type": 0,
"color": "warning",
"is_value": true,
"status": true,
"sort": 5,
"remark": null,
"children": []
},
{
"label": "保存",
"value": "Save",
"parent": 4,
"type": 0,
"color": "success",
"is_value": true,
"status": true,
"sort": 6,
"remark": null,
"children": []
},
{
"label": "导入",
"value": "Import",
"parent": 4,
"type": 0,
"color": "primary",
"is_value": true,
"status": true,
"sort": 7,
"remark": null,
"children": []
},
{
"label": "导出",
"value": "Export",
"parent": 4,
"type": 0,
"color": "warning",
"is_value": true,
"status": true,
"sort": 8,
"remark": null,
"children": []
}
]
},
{
"label": "启用/禁用-数字值",
"value": "button_status_number",
"parent": null,
"type": 0,
"color": null,
"is_value": false,
"status": true,
"sort": 3,
"remark": null,
"children": [
{
"label": "启用",
"value": "1",
"parent": 13,
"type": 1,
"color": "success",
"is_value": true,
"status": true,
"sort": 1,
"remark": null,
"children": []
},
{
"label": "禁用",
"value": "0",
"parent": 13,
"type": 1,
"color": "danger",
"is_value": true,
"status": true,
"sort": 2,
"remark": null,
"children": []
}
]
},
{
"label": "是/否-布尔值",
"value": "button_whether_bool",
"parent": null,
"type": 0,
"color": null,
"is_value": false,
"status": true,
"sort": 4,
"remark": null,
"children": [
{
"label": "是",
"value": "true",
"parent": 16,
"type": 6,
"color": "success",
"is_value": true,
"status": true,
"sort": 1,
"remark": null,
"children": []
},
{
"label": "否",
"value": "false",
"parent": 16,
"type": 6,
"color": "danger",
"is_value": true,
"status": true,
"sort": 2,
"remark": null,
"children": []
}
]
},
{
"label": "是/否-数字值",
"value": "button_whether_number",
"parent": null,
"type": 0,
"color": null,
"is_value": false,
"status": true,
"sort": 5,
"remark": null,
"children": [
{
"label": "是",
"value": "1",
"parent": 19,
"type": 1,
"color": "success",
"is_value": true,
"status": true,
"sort": 1,
"remark": null,
"children": []
},
{
"label": "否",
"value": "2",
"parent": 19,
"type": 1,
"color": "danger",
"is_value": true,
"status": true,
"sort": 2,
"remark": null,
"children": []
}
]
},
{
"label": "用户类型",
"value": "user_type",
"parent": null,
"type": 0,
"color": null,
"is_value": false,
"status": true,
"sort": 6,
"remark": null,
"children": [
{
"label": "后台用户",
"value": "0",
"parent": 22,
"type": 1,
"color": null,
"is_value": true,
"status": true,
"sort": 1,
"remark": null,
"children": []
},
{
"label": "前台用户",
"value": "1",
"parent": 22,
"type": 1,
"color": null,
"is_value": true,
"status": true,
"sort": 2,
"remark": null,
"children": []
}
]
},
{
"label": "表单类型",
"value": "config_form_type",
"parent": null,
"type": 0,
"color": null,
"is_value": false,
"status": true,
"sort": 7,
"remark": null,
"children": [
{
"label": "text",
"value": "0",
"parent": 25,
"type": 1,
"color": null,
"is_value": true,
"status": true,
"sort": 0,
"remark": null,
"children": []
},
{
"label": "textarea",
"value": "3",
"parent": 25,
"type": 1,
"color": "",
"is_value": true,
"status": true,
"sort": 0,
"remark": null,
"children": []
},
{
"label": "number",
"value": "10",
"parent": 25,
"type": 1,
"color": "",
"is_value": true,
"status": true,
"sort": 0,
"remark": null,
"children": []
},
{
"label": "datetime",
"value": "1",
"parent": 25,
"type": 1,
"color": null,
"is_value": true,
"status": true,
"sort": 1,
"remark": null,
"children": []
},
{
"label": "date",
"value": "2",
"parent": 25,
"type": 1,
"color": null,
"is_value": true,
"status": true,
"sort": 2,
"remark": null,
"children": []
},
{
"label": "time",
"value": "15",
"parent": 25,
"type": 1,
"color": "",
"is_value": true,
"status": true,
"sort": 3,
"remark": null,
"children": []
},
{
"label": "select",
"value": "4",
"parent": 25,
"type": 1,
"color": null,
"is_value": true,
"status": true,
"sort": 4,
"remark": null,
"children": []
},
{
"label": "checkbox",
"value": "5",
"parent": 25,
"type": 1,
"color": null,
"is_value": true,
"status": true,
"sort": 5,
"remark": null,
"children": []
},
{
"label": "radio",
"value": "6",
"parent": 25,
"type": 1,
"color": null,
"is_value": true,
"status": true,
"sort": 6,
"remark": null,
"children": []
},
{
"label": "switch",
"value": "9",
"parent": 25,
"type": 1,
"color": "",
"is_value": true,
"status": true,
"sort": 6,
"remark": null,
"children": []
},
{
"label": "文件附件",
"value": "8",
"parent": 25,
"type": 1,
"color": "",
"is_value": true,
"status": true,
"sort": 7,
"remark": null,
"children": []
},
{
"label": "图片(单张)",
"value": "7",
"parent": 25,
"type": 1,
"color": "",
"is_value": true,
"status": true,
"sort": 8,
"remark": null,
"children": []
},
{
"label": "图片(多张)",
"value": "12",
"parent": 25,
"type": 1,
"color": "",
"is_value": true,
"status": true,
"sort": 9,
"remark": null,
"children": []
},
{
"label": "数组",
"value": "11",
"parent": 25,
"type": 1,
"color": "",
"is_value": true,
"status": true,
"sort": 11,
"remark": null,
"children": []
},
{
"label": "关联表",
"value": "13",
"parent": 25,
"type": 1,
"color": "",
"is_value": true,
"status": true,
"sort": 13,
"remark": null,
"children": []
},
{
"label": "关联表(多选)",
"value": "14",
"parent": 25,
"type": 1,
"color": "",
"is_value": true,
"status": true,
"sort": 14,
"remark": null,
"children": []
}
]
},
{
"label": "性别",
"value": "gender",
"parent": null,
"type": 0,
"color": null,
"is_value": false,
"status": true,
"sort": 8,
"remark": null,
"children": [
{
"label": "未知",
"value": "0",
"parent": 42,
"type": 1,
"color": null,
"is_value": true,
"status": true,
"sort": 0,
"remark": null,
"children": []
},
{
"label": "男",
"value": "1",
"parent": 42,
"type": 1,
"color": null,
"is_value": true,
"status": true,
"sort": 1,
"remark": null,
"children": []
},
{
"label": "女",
"value": "2",
"parent": 42,
"type": 1,
"color": null,
"is_value": true,
"status": true,
"sort": 2,
"remark": null,
"children": []
}
]
}
]

View File

@@ -0,0 +1,646 @@
[
{
"name": "系统管理",
"icon": "iconfont icon-xitongshezhi",
"sort": 1,
"is_link": false,
"is_catalog": true,
"web_path": "/system",
"component": "",
"component_name": "",
"status": true,
"cache": false,
"visible": true,
"parent": null,
"children": [
{
"name": "菜单管理",
"icon": "iconfont icon-caidan",
"sort": 1,
"is_link": false,
"is_catalog": false,
"web_path": "/menu",
"component": "system/menu/index",
"component_name": "menu",
"status": true,
"cache": false,
"visible": true,
"parent": 41,
"children": [],
"menu_button": [
{
"name": "查询",
"value": "menu:Search",
"api": "/api/system/menu/",
"method": 0
},
{
"name": "详情",
"value": "menu:Retrieve",
"api": "/api/system/menu/{id}/",
"method": 0
},
{
"name": "新增",
"value": "menu:Create",
"api": "/api/system/menu/",
"method": 1
},
{
"name": "编辑",
"value": "menu:Update",
"api": "/api/system/menu/{id}/",
"method": 2
},
{
"name": "删除",
"value": "menu:Delete",
"api": "/api/system/menu/{id}/",
"method": 3
}
]
},
{
"name": "菜单按钮",
"icon": "dot-circle-o",
"sort": 2,
"is_link": false,
"is_catalog": false,
"web_path": "/menuButton",
"component": "system/menuButton/index",
"component_name": "menuButton",
"status": true,
"cache": false,
"visible": false,
"parent": 41,
"children": [],
"menu_button": [
{
"name": "查询",
"value": "menu_button:Search",
"api": "/api/system/menu_button/",
"method": 0
},
{
"name": "新增",
"value": "menu_button:Create",
"api": "/api/system/menu_button/",
"method": 1
},
{
"name": "编辑",
"value": "menu_button:Update",
"api": "/api/system/menu_button/{id}/",
"method": 2
},
{
"name": "删除",
"value": "menu_button:Delete",
"api": "/api/system/menu_button/{id}/",
"method": 3
}
]
},
{
"name": "部门管理",
"icon": "ele-OfficeBuilding",
"sort": 3,
"is_link": false,
"is_catalog": false,
"web_path": "/dept",
"component": "system/dept/index",
"component_name": "dept",
"status": true,
"cache": false,
"visible": true,
"parent": 41,
"children": [],
"menu_button": [
{
"name": "查询",
"value": "dept:Search",
"api": "/api/system/dept/",
"method": 0
},
{
"name": "详情",
"value": "dept:Retrieve",
"api": "/api/system/dept/{id}/",
"method": 0
},
{
"name": "新增",
"value": "dept:Create",
"api": "/api/system/dept/",
"method": 1
},
{
"name": "编辑",
"value": "dept:Update",
"api": "/api/system/dept/{id}/",
"method": 2
},
{
"name": "删除",
"value": "dept:Delete",
"api": "/api/system/dept/{id}/",
"method": 3
}
]
},
{
"name": "角色管理",
"icon": "ele-ColdDrink",
"sort": 4,
"is_link": false,
"is_catalog": false,
"web_path": "/role",
"component": "system/role/index",
"component_name": "role",
"status": true,
"cache": false,
"visible": true,
"parent": 41,
"children": [],
"menu_button": [
{
"name": "查询",
"value": "role:Search",
"api": "/api/system/role/",
"method": 0
},
{
"name": "详情",
"value": "role:Retrieve",
"api": "/api/system/role/{id}/",
"method": 0
},
{
"name": "新增",
"value": "role:Create",
"api": "/api/system/role/",
"method": 1
},
{
"name": "编辑",
"value": "role:Update",
"api": "/api/system/role/{id}/",
"method": 2
},
{
"name": "保存",
"value": "role:Save",
"api": "/api/system/role/{id}/",
"method": 2
},
{
"name": "删除",
"value": "role:Delete",
"api": "/api/system/role/{id}/",
"method": 3
}
]
},
{
"name": "用户管理",
"icon": "iconfont icon-icon-",
"sort": 6,
"is_link": false,
"is_catalog": false,
"web_path": "/user",
"component": "system/user/index",
"component_name": "user",
"status": true,
"cache": false,
"visible": true,
"parent": 41,
"children": [],
"menu_button": [
{
"name": "查询",
"value": "user:Search",
"api": "/api/system/user/",
"method": 0
},
{
"name": "详情",
"value": "user:Retrieve",
"api": "/api/system/user/{id}/",
"method": 0
},
{
"name": "新增",
"value": "user:Create",
"api": "/api/system/user/",
"method": 1
},
{
"name": "导出",
"value": "user:Export",
"api": "/api/system/user/export/",
"method": 1
},
{
"name": "导入",
"value": "user:Import",
"api": "/api/system/user/import/",
"method": 1
},
{
"name": "编辑",
"value": "user:Update",
"api": "/api/system/user/{id}/",
"method": 2
},
{
"name": "重设密码",
"value": "user:ResetPassword",
"api": "/api/system/user/{id}/reset_password/",
"method": 2
},
{
"name": "重置密码",
"value": "user:DefaultPassword",
"api": "/api/system/user/{id}/reset_to_default_password/",
"method": 2
},
{
"name": "删除",
"value": "user:Delete",
"api": "/api/system/user/{id}/",
"method": 3
}
]
},
{
"name": "消息中心",
"icon": "iconfont icon-xiaoxizhongxin",
"sort": 7,
"is_link": false,
"is_catalog": false,
"web_path": "/messageCenter",
"component": "system/messageCenter/index",
"component_name": "messageCenter",
"status": true,
"cache": false,
"visible": true,
"parent": 41,
"children": [],
"menu_button": [
{
"name": "查询",
"value": "messageCenter:Search",
"api": "/api/system/message_center/",
"method": 0
},
{
"name": "详情",
"value": "messageCenter:Retrieve",
"api": "/api/system/message_center/{id}/",
"method": 0
},
{
"name": "新增",
"value": "messageCenter:Create",
"api": "/api/system/message_center/",
"method": 1
},
{
"name": "编辑",
"value": "messageCenter:Update",
"api": "/api/system/message_center/{id}/",
"method": 2
},
{
"name": "删除",
"value": "messageCenter:Delete",
"api": "/api/system/menu/{id}/",
"method": 3
}
]
},
{
"name": "接口白名单",
"icon": "ele-SetUp",
"sort": 8,
"is_link": false,
"is_catalog": false,
"web_path": "/apiWhiteList",
"component": "system/whiteList/index",
"component_name": "whiteList",
"status": true,
"cache": false,
"visible": true,
"parent": 41,
"children": [],
"menu_button": [
{
"name": "查询",
"value": "api_white_list:Search",
"api": "/api/system/api_white_list/",
"method": 0
},
{
"name": "详情",
"value": "api_white_list:Retrieve",
"api": "/api/system/api_white_list/{id}/",
"method": 0
},
{
"name": "新增",
"value": "api_white_list:Create",
"api": "/api/system/api_white_list/",
"method": 1
},
{
"name": "编辑",
"value": "api_white_list:Update",
"api": "/api/system/api_white_list/{id}/",
"method": 2
},
{
"name": "删除",
"value": "api_white_list:Delete",
"api": "/api/system/api_white_list/{id}/",
"method": 3
}
]
}
],
"menu_button": []
},
{
"name": "常规配置",
"icon": "iconfont icon-configure",
"sort": 2,
"is_link": false,
"is_catalog": true,
"web_path": "/generalConfig",
"component": "",
"component_name": "",
"status": true,
"cache": false,
"visible": true,
"parent": null,
"children": [
{
"name": "系统配置",
"icon": "iconfont icon-system",
"sort": 0,
"is_link": false,
"is_catalog": false,
"web_path": "/config",
"component": "system/config/index",
"component_name": "config",
"status": true,
"cache": false,
"visible": true,
"parent": 49,
"children": [],
"menu_button": [
{
"name": "查询",
"value": "system_config:Search",
"api": "/api/system/system_config/",
"method": 0
},
{
"name": "详情",
"value": "system_config:Retrieve",
"api": "/api/system/system_config/{id}/",
"method": 0
},
{
"name": "新增",
"value": "system_config:Create",
"api": "/api/system/system_config/",
"method": 1
},
{
"name": "编辑",
"value": "system_config:Update",
"api": "/api/system/system_config/{id}/",
"method": 2
},
{
"name": "删除",
"value": "system_config:Delete",
"api": "/api/system/system_config/{id}/",
"method": 3
}
]
},
{
"name": "字典管理",
"icon": "iconfont icon-dict",
"sort": 1,
"is_link": false,
"is_catalog": false,
"web_path": "/dictionary",
"component": "system/dictionary/index",
"component_name": "dictionary",
"status": true,
"cache": false,
"visible": true,
"parent": 49,
"children": [],
"menu_button": [
{
"name": "查询",
"value": "dictionary:Search",
"api": "/api/system/dictionary/",
"method": 0
},
{
"name": "详情",
"value": "dictionary:Retrieve",
"api": "/api/system/dictionary/{id}/",
"method": 0
},
{
"name": "新增",
"value": "dictionary:Create",
"api": "/api/system/dictionary/",
"method": 1
},
{
"name": "编辑",
"value": "dictionary:Update",
"api": "/api/system/dictionary/{id}/",
"method": 2
},
{
"name": "删除",
"value": "dictionary:Delete",
"api": "/api/system/dictionary/{id}/",
"method": 3
}
]
},
{
"name": "地区管理",
"icon": "iconfont icon-Area",
"sort": 2,
"is_link": false,
"is_catalog": false,
"web_path": "/areas",
"component": "system/areas/index",
"component_name": "areas",
"status": true,
"cache": false,
"visible": true,
"parent": 49,
"children": [],
"menu_button": [
{
"name": "查询",
"value": "area:Search",
"api": "/api/system/area/",
"method": 0
},
{
"name": "详情",
"value": "area:Retrieve",
"api": "/api/system/area/{id}/",
"method": 0
},
{
"name": "新增",
"value": "area:Create",
"api": "/api/system/area/",
"method": 1
},
{
"name": "编辑",
"value": "area:Update",
"api": "/api/system/area/{id}/",
"method": 2
},
{
"name": "删除",
"value": "area:Delete",
"api": "/api/system/area/{id}/",
"method": 3
}
]
},
{
"name": "附件管理",
"icon": "iconfont icon-file",
"sort": 3,
"is_link": false,
"is_catalog": false,
"web_path": "/file",
"component": "system/fileList/index",
"component_name": "file",
"status": true,
"cache": false,
"visible": true,
"parent": 49,
"children": [],
"menu_button": [
{
"name": "详情",
"value": "file:Retrieve",
"api": "/api/system/file/{id}/",
"method": 0
},
{
"name": "查询",
"value": "file:Search",
"api": "/api/system/file/",
"method": 0
},
{
"name": "编辑",
"value": "file:Update",
"api": "/api/system/file/{id}/",
"method": 1
},
{
"name": "删除",
"value": "file:Delete",
"api": "/api/system/file/{id}/",
"method": 3
}
]
}
],
"menu_button": []
},
{
"name": "日志管理",
"icon": "iconfont icon-rizhi",
"sort": 3,
"is_link": false,
"is_catalog": true,
"web_path": "/log",
"component": "",
"component_name": "",
"status": true,
"cache": false,
"visible": true,
"parent": null,
"children": [
{
"name": "登录日志",
"icon": "iconfont icon-guanlidenglurizhi",
"sort": 1,
"is_link": false,
"is_catalog": false,
"web_path": "/loginLog",
"component": "system/log/loginLog/index",
"component_name": "loginLog",
"status": true,
"cache": false,
"visible": true,
"parent": 54,
"children": [],
"menu_button": [
{
"name": "查询",
"value": "login_log:Search",
"api": "/api/system/login_log/",
"method": 0
},
{
"name": "详情",
"value": "login_log:Retrieve",
"api": "/api/system/login_log/{id}/",
"method": 0
}
]
},
{
"name": "操作日志",
"icon": "iconfont icon-caozuorizhi",
"sort": 2,
"is_link": false,
"is_catalog": false,
"web_path": "/operationLog",
"component": "system/log/operationLog/index",
"component_name": "operationLog",
"status": true,
"cache": false,
"visible": true,
"parent": 54,
"children": [],
"menu_button": [
{
"name": "详情",
"value": "operation_log:Retrieve",
"api": "/api/system/operation_log/{id}/",
"method": 0
},
{
"name": "查询",
"value": "operation_log:Search",
"api": "/api/system/operation_log/",
"method": 0
}
]
}
],
"menu_button": []
}
]

View File

@@ -0,0 +1,18 @@
[
{
"name": "管理员",
"key": "admin",
"sort": 1,
"status": true,
"admin": true,
"remark": null
},
{
"name": "用户",
"key": "public",
"sort": 2,
"status": true,
"admin": true,
"remark": null
}
]

View File

@@ -0,0 +1,12 @@
[
{
"role_key": "admin",
"menu_button_value": "menu:Search",
"data_range": 0
},
{
"role_key": "public",
"menu_button_value":"menu:Search",
"data_range": 0
}
]

View File

@@ -0,0 +1,10 @@
[
{
"role_key": "admin",
"menu_component_name": "menu"
},
{
"role_key": "public",
"menu_component_name": "menu"
}
]

View File

@@ -0,0 +1,197 @@
[
{
"parent": null,
"title": "基础配置",
"key": "base",
"value": null,
"sort": 0,
"status": true,
"data_options": null,
"form_item_type": 0,
"rule": null,
"placeholder": null,
"setting": null,
"children": [
{
"parent": 10,
"title": "开启验证码",
"key": "captcha_state",
"value": true,
"sort": 1,
"status": true,
"data_options": null,
"form_item_type": 9,
"rule": [
{
"message": "必填项不能为空",
"required": true
}
],
"placeholder": "请选择",
"setting": null,
"children": []
},
{
"parent": 10,
"title": "创建用户默认密码",
"key": "default_password",
"value": "admin123456",
"sort": 2,
"status": true,
"data_options": null,
"form_item_type": 0,
"rule": [
{
"message": "必填项不能为空",
"required": true
}
],
"placeholder": "请输入默认密码",
"setting": null,
"children": []
}
]
},
{
"parent": null,
"title": "登录页配置",
"key": "login",
"value": null,
"sort": 1,
"status": true,
"data_options": null,
"form_item_type": 0,
"rule": null,
"placeholder": null,
"setting": null,
"children": [
{
"parent": 1,
"title": "网站名称",
"key": "site_name",
"value": "企业级后台管理系统",
"sort": 1,
"status": true,
"data_options": null,
"form_item_type": 0,
"rule": [
{
"message": "必填项不能为空",
"required": true
}
],
"placeholder": "请输入网站名称",
"setting": null,
"children": []
},
{
"parent": 1,
"title": "登录网站logo",
"key": "site_logo",
"value": null,
"sort": 2,
"status": true,
"data_options": null,
"form_item_type": 7,
"rule": [],
"placeholder": "请上传网站logo",
"setting": null,
"children": []
},
{
"parent": 1,
"title": "登录页背景图",
"key": "login_background",
"value": null,
"sort": 3,
"status": true,
"data_options": null,
"form_item_type": 7,
"rule": [],
"placeholder": "请上传登录背景页",
"setting": null,
"children": []
},
{
"parent": 1,
"title": "版权信息",
"key": "copyright",
"value": "2021-2022 django-vue-admin.com 版权所有",
"sort": 4,
"status": true,
"data_options": null,
"form_item_type": 0,
"rule": [
{
"message": "必填项不能为空",
"required": true
}
],
"placeholder": "请输入版权信息",
"setting": null,
"children": []
},
{
"parent": 1,
"title": "备案信息",
"key": "keep_record",
"value": "晋ICP备18005113号-3",
"sort": 5,
"status": true,
"data_options": null,
"form_item_type": 0,
"rule": [
{
"message": "必填项不能为空",
"required": true
}
],
"placeholder": "请输入备案信息",
"setting": null,
"children": []
},
{
"parent": 1,
"title": "帮助链接",
"key": "help_url",
"value": "https://django-vue-admin.com",
"sort": 6,
"status": true,
"data_options": null,
"form_item_type": 0,
"rule": "",
"placeholder": "请输入帮助信息",
"setting": null,
"children": []
},
{
"parent": 1,
"title": "隐私链接",
"key": "privacy_url",
"value": "#",
"sort": 7,
"status": true,
"data_options": null,
"form_item_type": 0,
"rule": [],
"placeholder": "请填写隐私链接",
"setting": null,
"children": []
},
{
"parent": 1,
"title": "条款链接",
"key": "clause_url",
"value": "#",
"sort": 8,
"status": true,
"data_options": null,
"form_item_type": 0,
"rule": [],
"placeholder": "请输入条款链接",
"setting": null,
"children": []
}
]
}
]

View File

@@ -0,0 +1,59 @@
[
{
"username": "superadmin",
"email": "dvadmin@django-vue-admin.com",
"mobile": "13333333333",
"avatar": null,
"name": "超级管理员",
"gender": 1,
"user_type": 0,
"role": [],
"role_key": [
"admin"
],
"dept_key": "dvadmin",
"first_name": "",
"last_name": "",
"is_staff": true,
"is_active": true,
"password": "pbkdf2_sha256$260000$g17x5wlSiW1FZAh1Eudchw$ZeSAqj3Xak0io8v/pmPW0BX9EX5R2zFXDwbbD68oBFk=",
"last_login": null,
"is_superuser": true
},
{
"username": "admin",
"email": "dvadmin@django-vue-admin.com",
"mobile": "18888888888",
"avatar": "",
"name": "管理员",
"gender": 1,
"user_type": 0,
"role": [],
"first_name": "",
"last_name": "",
"is_staff": true,
"is_active": true,
"password": "pbkdf2_sha256$260000$g17x5wlSiW1FZAh1Eudchw$ZeSAqj3Xak0io8v/pmPW0BX9EX5R2zFXDwbbD68oBFk=",
"last_login": null,
"is_superuser": false
},
{
"username": "test",
"email": "dvadmin@django-vue-admin.com",
"mobile": "18888888888",
"avatar": "",
"name": "测试人员",
"gender": 1,
"user_type": 0,
"role": [],
"role_key": ["public"],
"dept_key": "technology",
"first_name": "",
"last_name": "",
"is_staff": true,
"is_active": true,
"password": "pbkdf2_sha256$260000$g17x5wlSiW1FZAh1Eudchw$ZeSAqj3Xak0io8v/pmPW0BX9EX5R2zFXDwbbD68oBFk=",
"last_login": null,
"is_superuser": false
}
]

View File

@@ -0,0 +1,86 @@
# 初始化
import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "application.settings")
django.setup()
from dvadmin.utils.core_initialize import CoreInitialize
from dvadmin.system.fixtures.initSerializer import UsersInitSerializer, DeptInitSerializer, RoleInitSerializer, \
MenuInitSerializer, ApiWhiteListInitSerializer, DictionaryInitSerializer, SystemConfigInitSerializer, \
RoleMenuInitSerializer, RoleMenuButtonInitSerializer
class Initialize(CoreInitialize):
def init_dept(self):
"""
初始化部门信息
"""
self.init_base(DeptInitSerializer, unique_fields=['name', 'parent','key'])
def init_role(self):
"""
初始化角色信息
"""
self.init_base(RoleInitSerializer, unique_fields=['key'])
def init_users(self):
"""
初始化用户信息
"""
self.init_base(UsersInitSerializer, unique_fields=['username'])
def init_menu(self):
"""
初始化菜单信息
"""
self.init_base(MenuInitSerializer, unique_fields=['name', 'web_path', 'component', 'component_name'])
def init_role_menu(self):
"""
初始化角色菜单信息
"""
self.init_base(RoleMenuInitSerializer, unique_fields=['role', 'menu'])
def init_role_menu_button(self):
"""
初始化角色菜单按钮信息
"""
self.init_base(RoleMenuButtonInitSerializer, unique_fields=['role', 'menu_button'])
def init_api_white_list(self):
"""
初始API白名单
"""
self.init_base(ApiWhiteListInitSerializer, unique_fields=['url', 'method', ])
def init_dictionary(self):
"""
初始化字典表
"""
self.init_base(DictionaryInitSerializer, unique_fields=['value', 'parent', ])
def init_system_config(self):
"""
初始化系统配置表
"""
self.init_base(SystemConfigInitSerializer, unique_fields=['key', 'parent', ])
def run(self):
self.init_dept()
self.init_role()
self.init_users()
self.init_menu()
self.init_role_menu()
self.init_role_menu_button()
self.init_api_white_list()
self.init_dictionary()
self.init_system_config()
if __name__ == "__main__":
Initialize(app='dvadmin.system').run()

View File

@@ -0,0 +1,95 @@
import json
import logging
import os
import django
from django.db.models import QuerySet
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
django.setup()
from django.core.management.base import BaseCommand
from application.settings import BASE_DIR
from dvadmin.system.models import Menu, Users, Dept, Role, ApiWhiteList, Dictionary, SystemConfig
from dvadmin.system.fixtures.initSerializer import UsersInitSerializer, DeptInitSerializer, RoleInitSerializer, \
MenuInitSerializer, ApiWhiteListInitSerializer, DictionaryInitSerializer, SystemConfigInitSerializer, \
RoleMenuInitSerializer, RoleMenuButtonInitSerializer
logger = logging.getLogger(__name__)
class Command(BaseCommand):
"""
生产初始化菜单: python3 manage.py generate_init_json 生成初始化的model名
例如:
全部生成python3 manage.py generate_init_json
只生成某个model的 python3 manage.py generate_init_json users
"""
def serializer_data(self, serializer, query_set: QuerySet):
serializer = serializer(query_set, many=True)
data = json.loads(json.dumps(serializer.data, ensure_ascii=False))
with open(os.path.join(BASE_DIR, f'init_{query_set.model._meta.model_name}.json'), 'w') as f:
json.dump(data, f, indent=4, ensure_ascii=False)
return
def add_arguments(self, parser):
parser.add_argument("generate_name", nargs="*", type=str, help="初始化生成的表名")
def generate_users(self):
self.serializer_data(UsersInitSerializer, Users.objects.all())
def generate_role(self):
self.serializer_data(RoleInitSerializer, Role.objects.all())
def generate_dept(self):
self.serializer_data(DeptInitSerializer, Dept.objects.filter(parent_id__isnull=True))
def generate_menu(self):
self.serializer_data(MenuInitSerializer, Menu.objects.filter(parent_id__isnull=True))
def generate_api_white_list(self):
self.serializer_data(ApiWhiteListInitSerializer, ApiWhiteList.objects.all())
def generate_dictionary(self):
self.serializer_data(DictionaryInitSerializer, Dictionary.objects.filter(parent_id__isnull=True))
def generate_system_config(self):
self.serializer_data(SystemConfigInitSerializer, SystemConfig.objects.filter(parent_id__isnull=True))
def handle(self, *args, **options):
generate_name = options.get('generate_name')
generate_name_dict = {
"users": self.generate_users,
"role": self.generate_role,
"dept": self.generate_dept,
"menu": self.generate_menu,
"api_white_list": self.generate_api_white_list,
"dictionary": self.generate_dictionary,
"system_config": self.generate_system_config,
}
if not generate_name:
for ele in generate_name_dict.keys():
generate_name_dict[ele]()
return
for generate_name in generate_name:
if generate_name not in generate_name_dict:
print(f"该初始化方法尚未配置\n{generate_name_dict}")
raise Exception(f"该初始化方法尚未配置,已配置项:{list(generate_name_dict.keys())}")
generate_name_dict[generate_name]()
return
if __name__ == '__main__':
# with open(os.path.join(BASE_DIR, 'temp_init_menu.json')) as f:
# for menu_data in json.load(f):
# menu_data['creator'] = 1
# menu_data['modifier'] = 1
# menu_data['dept_belong_id'] = 1
# request.user = Users.objects.order_by('create_datetime').first()
# serializer = MenuInitSerializer(data=menu_data, request=request)
# serializer.is_valid(raise_exception=True)
# serializer.save()
a = Users.objects.filter()
print(type(Users.objects.filter()))

View File

@@ -0,0 +1,53 @@
import logging
from django.core.management.base import BaseCommand
from application import settings
logger = logging.getLogger(__name__)
class Command(BaseCommand):
"""
项目初始化命令: python manage.py init
"""
def add_arguments(self, parser):
parser.add_argument(
"init_name",
nargs="*",
type=str,
)
parser.add_argument("-y", nargs="*")
parser.add_argument("-Y", nargs="*")
parser.add_argument("-n", nargs="*")
parser.add_argument("-N", nargs="*")
def handle(self, *args, **options):
reset = False
if isinstance(options.get("y"), list) or isinstance(options.get("Y"), list):
reset = True
if isinstance(options.get("n"), list) or isinstance(options.get("N"), list):
reset = False
for app in settings.INSTALLED_APPS:
try:
exec(
f"""
from {app}.fixtures.initialize import Initialize
Initialize(reset={reset},app="{app}").run()
"""
)
except ModuleNotFoundError:
# 兼容之前版本初始化
try:
exec(
f"""
from {app}.initialize import main
main(reset={reset})
"""
)
except ModuleNotFoundError:
pass
print("初始化数据完成!")

View File

@@ -0,0 +1,83 @@
# 城市联动
"""
到乡级 使用方法
1. https://www.npmjs.com/package/china-division 下载数据把对应的json放入对应目录
2. 修改此文件中对应json名
3. 右击执行此py文件进行初始化
"""
import json
import os
import django
import pypinyin
from django.core.management import BaseCommand
from django.db import connection
from application import dispatch
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
django.setup()
from application.settings import BASE_DIR
from dvadmin.system.models import Area
area_code_list = []
def area_list(code_list, pcode=None, depth=1):
"""
递归获取所有列表
"""
for code_dict in code_list:
code = code_dict.get('code', None)
name = code_dict.get('name', None)
children = code_dict.get('children', None)
pinyin = ''.join([''.join(i) for i in pypinyin.pinyin(name, style=pypinyin.NORMAL)])
area_code_list.append(
{
"name": name,
"code": code,
"level": depth,
"pinyin": pinyin,
"initials": pinyin[0].upper() if pinyin else "#",
"pcode_id": pcode,
}
)
if children:
area_list(code_list=children, pcode=code, depth=depth + 1)
def main():
with open(os.path.join(BASE_DIR, 'dvadmin', 'system', 'util', 'pca-code.json'), 'r', encoding="utf-8") as load_f:
code_list = json.load(load_f)
area_list(code_list)
if Area.objects.count() == 0:
Area.objects.bulk_create([Area(**ele) for ele in area_code_list])
else:
for ele in area_code_list:
code = ele.pop("code")
Area.objects.update_or_create(code=code, defaults=ele)
class Command(BaseCommand):
"""
项目初始化命令: python manage.py init
"""
def add_arguments(self, parser):
pass
def handle(self, *args, **options):
print(f"正在准备初始化省份数据...")
if dispatch.is_tenants_mode():
from django_tenants.utils import get_tenant_model
from django_tenants.utils import tenant_context
for tenant in get_tenant_model().objects.exclude(schema_name='public'):
with tenant_context(tenant):
print(f"租户[{connection.tenant.schema_name}]初始化数据开始...")
main()
print(f"租户[{connection.tenant.schema_name}]初始化数据完成!")
else:
main()
print("省份数据初始化数据完成!")

View File

@@ -0,0 +1,556 @@
import hashlib
import os
from django.contrib.auth.models import AbstractUser, UserManager
from django.db import models
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from application import dispatch
from dvadmin.utils.models import CoreModel, table_prefix
STATUS_CHOICES = (
(0, "禁用"),
(1, "启用"),
)
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="权限字符")
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")
class Meta:
db_table = table_prefix + "system_role"
verbose_name = "角色表"
verbose_name_plural = verbose_name
ordering = ("sort",)
class CustomUserManager(UserManager):
def create_superuser(self, username, email=None, password=None, **extra_fields):
user = super(CustomUserManager, self).create_superuser(username, email, password, **extra_fields)
user.set_password(password)
try:
user.role.add(Role.objects.get(name="管理员"))
user.save(using=self._db)
return user
except ObjectDoesNotExist:
user.delete()
raise ValidationError("角色`管理员`不存在, 创建失败, 请先执行python manage.py init")
class Users(CoreModel, AbstractUser):
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="性别"
)
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", blank=True, verbose_name="关联岗位", db_constraint=False,
help_text="关联岗位")
role = models.ManyToManyField(to="Role", blank=True, 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="关联部门",
)
objects = CustomUserManager()
def set_password(self, raw_password):
super().set_password(hashlib.md5(raw_password.encode(encoding="UTF-8")).hexdigest())
class Meta:
db_table = table_prefix + "system_users"
verbose_name = "用户表"
verbose_name_plural = verbose_name
ordering = ("-create_datetime",)
class Post(CoreModel):
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="岗位状态")
class Meta:
db_table = table_prefix + "system_post"
verbose_name = "岗位表"
verbose_name_plural = verbose_name
ordering = ("sort",)
class Dept(CoreModel):
name = models.CharField(max_length=64, verbose_name="部门名称", help_text="部门名称")
key = models.CharField(max_length=64, unique=True, null=True, blank=True, 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="上级部门",
)
@classmethod
def recursion_all_dept(cls, dept_id: int, dept_all_list=None, dept_list=None):
"""
递归获取部门的所有下级部门
:param dept_id: 需要获取的id
:param dept_all_list: 所有列表
:param dept_list: 递归list
:return:
"""
if not dept_all_list:
dept_all_list = Dept.objects.values("id", "parent")
if dept_list is None:
dept_list = [dept_id]
for ele in dept_all_list:
if ele.get("parent") == dept_id:
dept_list.append(ele.get("id"))
cls.recursion_all_dept(ele.get("id"), dept_all_list, dept_list)
return list(set(dept_list))
class Meta:
db_table = table_prefix + "system_dept"
verbose_name = "部门表"
verbose_name_plural = verbose_name
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="菜单图标")
name = models.CharField(max_length=64, verbose_name="菜单名称", 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="侧边栏中是否显示")
class Meta:
db_table = table_prefix + "system_menu"
verbose_name = "菜单表"
verbose_name_plural = verbose_name
ordering = ("sort",)
class MenuButton(CoreModel):
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(unique=True, max_length=64, verbose_name="权限值", help_text="权限值")
api = models.CharField(max_length=200, verbose_name="接口地址", help_text="接口地址")
METHOD_CHOICES = (
(0, "GET"),
(1, "POST"),
(2, "PUT"),
(3, "DELETE"),
)
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_plural = verbose_name
ordering = ("-name",)
class RoleMenuPermission(CoreModel):
role = models.ForeignKey(
to="Role",
db_constraint=False,
related_name="role_menu",
on_delete=models.CASCADE,
verbose_name="关联角色",
help_text="关联角色",
)
menu = models.ForeignKey(
to="Menu",
db_constraint=False,
related_name="role_menu",
on_delete=models.CASCADE,
verbose_name="关联菜单",
help_text="关联菜单",
)
class Meta:
db_table = table_prefix + "role_menu_permission"
verbose_name = "角色菜单权限表"
verbose_name_plural = verbose_name
# ordering = ("-create_datetime",)
class RoleMenuButtonPermission(CoreModel):
role = models.ForeignKey(
to="Role",
db_constraint=False,
related_name="role_menu_button",
on_delete=models.CASCADE,
verbose_name="关联角色",
help_text="关联角色",
)
menu_button = models.ForeignKey(
to="MenuButton",
db_constraint=False,
related_name="menu_button_permission",
on_delete=models.CASCADE,
verbose_name="关联菜单按钮",
help_text="关联菜单按钮",
null=True,
blank=True
)
DATASCOPE_CHOICES = (
(0, "仅本人数据权限"),
(1, "本部门及以下数据权限"),
(2, "本部门数据权限"),
(3, "全部数据权限"),
(4, "自定数据权限"),
)
data_range = models.IntegerField(default=0, choices=DATASCOPE_CHOICES, verbose_name="数据权限范围",
help_text="数据权限范围")
dept = models.ManyToManyField(to="Dept", blank=True, verbose_name="数据权限-关联部门", db_constraint=False,
help_text="数据权限-关联部门")
class Meta:
db_table = table_prefix + "role_menu_button_permission"
verbose_name = "角色按钮权限表"
verbose_name_plural = verbose_name
ordering = ("-create_datetime",)
class Dictionary(CoreModel):
TYPE_LIST = (
(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="字典编号/实际值")
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="备注")
class Meta:
db_table = table_prefix + "system_dictionary"
verbose_name = "字典表"
verbose_name_plural = verbose_name
ordering = ("sort",)
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() # 有更新则刷新字典配置
def delete(self, using=None, keep_parents=False):
res = super().delete(using, keep_parents)
dispatch.refresh_dictionary()
return res
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="返回信息")
status = models.BooleanField(default=False, verbose_name="响应状态", help_text="响应状态")
class Meta:
db_table = table_prefix + "system_operation_log"
verbose_name = "操作日志"
verbose_name_plural = verbose_name
ordering = ("-create_datetime",)
def media_file_name(instance, filename):
h = instance.md5sum
basename, ext = os.path.splitext(filename)
return os.path.join("files", h[:1], h[1:2], h + ext.lower())
class FileList(CoreModel):
name = models.CharField(max_length=200, null=True, blank=True, verbose_name="名称", help_text="名称")
url = models.FileField(upload_to=media_file_name, null=True, blank=True,)
file_url = models.CharField(max_length=255, blank=True, verbose_name="文件地址", help_text="文件地址")
engine = models.CharField(max_length=100, default='local', blank=True, verbose_name="引擎", help_text="引擎")
mime_type = models.CharField(max_length=100, blank=True, verbose_name="Mime类型", help_text="Mime类型")
size = models.CharField(max_length=36, blank=True, verbose_name="文件大小", help_text="文件大小")
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
md5 = hashlib.md5()
for chunk in self.url.chunks():
md5.update(chunk)
self.md5sum = md5.hexdigest()
if not self.size:
self.size = self.url.size
if not self.file_url:
url = media_file_name(self,self.name)
self.file_url = f'media/{url}'
super(FileList, self).save(*args, **kwargs)
class Meta:
db_table = table_prefix + "system_file_list"
verbose_name = "文件管理"
verbose_name_plural = verbose_name
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乡级)")
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="父地区编码",
)
class Meta:
db_table = table_prefix + "system_area"
verbose_name = "地区表"
verbose_name_plural = verbose_name
ordering = ("code",)
def __str__(self):
return f"{self.name}"
class ApiWhiteList(CoreModel):
url = models.CharField(max_length=200, help_text="url地址", verbose_name="url")
METHOD_CHOICES = (
(0, "GET"),
(1, "POST"),
(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)
class Meta:
db_table = table_prefix + "api_white_list"
verbose_name = "接口白名单"
verbose_name_plural = verbose_name
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="父级",
)
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)
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"),
)
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="配置")
class Meta:
db_table = table_prefix + "system_config"
verbose_name = "系统配置表"
verbose_name_plural = verbose_name
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):
super().save(force_insert, force_update, using, update_fields)
dispatch.refresh_system_config() # 有更新则刷新系统配置
def delete(self, using=None, keep_parents=False):
res = super().delete(using, keep_parents)
dispatch.refresh_system_config()
return res
class LoginLog(CoreModel):
LOGIN_TYPE_CHOICES = ((1, "普通登录"), (2, "微信扫码登录"),)
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 = "登录日志"
verbose_name_plural = verbose_name
ordering = ("-create_datetime",)
class MessageCenter(CoreModel):
title = models.CharField(max_length=100, verbose_name="标题", help_text="标题")
content = models.TextField(verbose_name="内容", help_text="内容")
target_type = models.IntegerField(default=0, verbose_name="目标类型", help_text="目标类型")
target_user = models.ManyToManyField(to=Users, related_name='user', through='MessageCenterTargetUser',
through_fields=('messagecenter', 'users'), blank=True, verbose_name="目标用户",
help_text="目标用户")
target_dept = models.ManyToManyField(to=Dept, blank=True, db_constraint=False,
verbose_name="目标部门", help_text="目标部门")
target_role = models.ManyToManyField(to=Role, blank=True, db_constraint=False,
verbose_name="目标角色", help_text="目标角色")
class Meta:
db_table = table_prefix + "message_center"
verbose_name = "消息中心"
verbose_name_plural = verbose_name
ordering = ("-create_datetime",)
class MessageCenterTargetUser(CoreModel):
users = models.ForeignKey(Users, related_name="target_user", on_delete=models.CASCADE, db_constraint=False,
verbose_name="关联用户表", help_text="关联用户表")
messagecenter = models.ForeignKey(MessageCenter, on_delete=models.CASCADE, db_constraint=False,
verbose_name="关联消息中心表", help_text="关联消息中心表")
is_read = models.BooleanField(default=False, blank=True, null=True, verbose_name="是否已读", help_text="是否已读")
class Meta:
db_table = table_prefix + "message_center_target_user"
verbose_name = "消息中心目标用户表"
verbose_name_plural = verbose_name

View File

@@ -0,0 +1 @@
from django.test import TestCase

View File

@@ -0,0 +1,50 @@
from django.urls import path
from rest_framework import routers
from dvadmin.system.views.api_white_list import ApiWhiteListViewSet
from dvadmin.system.views.area import AreaViewSet
from dvadmin.system.views.dept import DeptViewSet
from dvadmin.system.views.dictionary import DictionaryViewSet
from dvadmin.system.views.file_list import FileViewSet
from dvadmin.system.views.login_log import LoginLogViewSet
from dvadmin.system.views.menu import MenuViewSet
from dvadmin.system.views.menu_button import MenuButtonViewSet
from dvadmin.system.views.message_center import MessageCenterViewSet
from dvadmin.system.views.operation_log import OperationLogViewSet
from dvadmin.system.views.role import RoleViewSet
from dvadmin.system.views.role_menu import RoleMenuPermissionViewSet
from dvadmin.system.views.role_menu_button_permission import RoleMenuButtonPermissionViewSet
from dvadmin.system.views.system_config import SystemConfigViewSet
from dvadmin.system.views.user import UserViewSet
system_url = routers.SimpleRouter()
system_url.register(r'menu', MenuViewSet)
system_url.register(r'menu_button', MenuButtonViewSet)
system_url.register(r'role', RoleViewSet)
system_url.register(r'dept', DeptViewSet)
system_url.register(r'user', UserViewSet)
system_url.register(r'operation_log', OperationLogViewSet)
system_url.register(r'dictionary', DictionaryViewSet)
system_url.register(r'area', AreaViewSet)
system_url.register(r'file', FileViewSet)
system_url.register(r'api_white_list', ApiWhiteListViewSet)
system_url.register(r'system_config', SystemConfigViewSet)
system_url.register(r'message_center',MessageCenterViewSet)
system_url.register(r'role_menu_button_permission', RoleMenuButtonPermissionViewSet)
system_url.register(r'role_menu_permission', RoleMenuPermissionViewSet)
urlpatterns = [
path('user/export/', UserViewSet.as_view({'post': 'export_data', })),
path('user/import/', UserViewSet.as_view({'get': 'import_data', 'post': 'import_data'})),
path('system_config/save_content/', SystemConfigViewSet.as_view({'put': 'save_content'})),
path('system_config/get_association_table/', SystemConfigViewSet.as_view({'get': 'get_association_table'})),
path('system_config/get_table_data/<int:pk>/', SystemConfigViewSet.as_view({'get': 'get_table_data'})),
path('system_config/get_relation_info/', SystemConfigViewSet.as_view({'get': 'get_relation_info'})),
path('login_log/', LoginLogViewSet.as_view({'get': 'list'})),
path('login_log/<int:pk>/', LoginLogViewSet.as_view({'get': 'retrieve'})),
path('dept_lazy_tree/', DeptViewSet.as_view({'get': 'dept_lazy_tree'})),
]
urlpatterns += system_url.urls

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
"""
@author: 猿小天
@contact: QQ:1638245306
@Created on: 2022/1/1 001 9:34
@Remark:
"""
from dvadmin.system.models import ApiWhiteList
from dvadmin.utils.serializers import CustomModelSerializer
from dvadmin.utils.viewset import CustomModelViewSet
class ApiWhiteListSerializer(CustomModelSerializer):
"""
接口白名单-序列化器
"""
class Meta:
model = ApiWhiteList
fields = "__all__"
read_only_fields = ["id"]
class ApiWhiteListViewSet(CustomModelViewSet):
"""
接口白名单
list:查询
create:新增
update:修改
retrieve:单例
destroy:删除
"""
queryset = ApiWhiteList.objects.all()
serializer_class = ApiWhiteListSerializer
# permission_classes = []

View File

@@ -0,0 +1,71 @@
# -*- coding: utf-8 -*-
from django.db.models import Q
from rest_framework import serializers
from dvadmin.system.models import Area
from dvadmin.utils.json_response import SuccessResponse
from dvadmin.utils.serializers import CustomModelSerializer
from dvadmin.utils.viewset import CustomModelViewSet
class AreaSerializer(CustomModelSerializer):
"""
地区-序列化器
"""
pcode_count = serializers.SerializerMethodField(read_only=True)
hasChild = serializers.SerializerMethodField()
def get_pcode_count(self, instance: Area):
return Area.objects.filter(pcode=instance).count()
def get_hasChild(self, instance):
hasChild = Area.objects.filter(pcode=instance.code)
if hasChild:
return True
return False
class Meta:
model = Area
fields = "__all__"
read_only_fields = ["id"]
class AreaCreateUpdateSerializer(CustomModelSerializer):
"""
地区管理 创建/更新时的列化器
"""
class Meta:
model = Area
fields = '__all__'
class AreaViewSet(CustomModelViewSet):
"""
地区管理接口
list:查询
create:新增
update:修改
retrieve:单例
destroy:删除
"""
queryset = Area.objects.all()
serializer_class = AreaSerializer
extra_filter_class = []
def get_queryset(self):
self.request.query_params._mutable = True
params = self.request.query_params
pcode = params.get('pcode', None)
page = params.get('page', None)
limit = params.get('limit', None)
if page:
del params['page']
if limit:
del params['limit']
if params:
if pcode:
queryset = self.queryset.filter(enable=True, pcode=pcode)
else:
queryset = self.queryset.filter(enable=True)
else:
queryset = self.queryset.filter(enable=True, pcode__isnull=True)
return queryset

View File

@@ -0,0 +1,157 @@
# -*- coding: utf-8 -*-
"""
@author: H0nGzA1
@contact: QQ:2505811377
@Remark: 部门管理
"""
from rest_framework import serializers
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from dvadmin.system.models import Dept, RoleMenuButtonPermission
from dvadmin.utils.json_response import DetailResponse, SuccessResponse
from dvadmin.utils.permission import AnonymousUserPermission
from dvadmin.utils.serializers import CustomModelSerializer
from dvadmin.utils.viewset import CustomModelViewSet
class DeptSerializer(CustomModelSerializer):
"""
部门-序列化器
"""
parent_name = serializers.CharField(read_only=True, source='parent.name')
status_label = serializers.SerializerMethodField()
has_children = serializers.SerializerMethodField()
hasChild = serializers.SerializerMethodField()
def get_hasChild(self, instance):
hasChild = Dept.objects.filter(parent=instance.id)
if hasChild:
return True
return False
def get_status_label(self, obj: Dept):
if obj.status:
return "启用"
return "禁用"
def get_has_children(self, obj: Dept):
return Dept.objects.filter(parent_id=obj.id).count()
class Meta:
model = Dept
fields = '__all__'
read_only_fields = ["id"]
class DeptImportSerializer(CustomModelSerializer):
"""
部门-导入-序列化器
"""
class Meta:
model = Dept
fields = '__all__'
read_only_fields = ["id"]
class DeptCreateUpdateSerializer(CustomModelSerializer):
"""
部门管理 创建/更新时的列化器
"""
def create(self, validated_data):
value = validated_data.get('parent',None)
if value is None:
validated_data['parent'] = self.request.user.dept
instance = super().create(validated_data)
instance.dept_belong_id = instance.id
instance.save()
return instance
class Meta:
model = Dept
fields = '__all__'
class DeptViewSet(CustomModelViewSet):
"""
部门管理接口
list:查询
create:新增
update:修改
retrieve:单例
destroy:删除
"""
queryset = Dept.objects.all()
serializer_class = DeptSerializer
create_serializer_class = DeptCreateUpdateSerializer
update_serializer_class = DeptCreateUpdateSerializer
filter_fields = ['name', 'id', 'parent']
search_fields = []
# extra_filter_class = []
import_serializer_class = DeptImportSerializer
import_field_dict = {
"name": "部门名称",
"key": "部门标识",
}
def list(self, request, *args, **kwargs):
# 如果懒加载,则只返回父级
request.query_params._mutable = True
params = request.query_params
parent = params.get('parent', None)
page = params.get('page', None)
limit = params.get('limit', None)
if page:
del params['page']
if limit:
del params['limit']
if params:
if parent:
queryset = self.queryset.filter(status=True, parent=parent)
else:
queryset = self.queryset.filter(status=True)
else:
queryset = self.queryset.filter(status=True, parent__isnull=True)
queryset = self.filter_queryset(queryset)
serializer = DeptSerializer(queryset, many=True, request=request)
data = serializer.data
return SuccessResponse(data=data)
@action(methods=["GET"], detail=False, permission_classes=[IsAuthenticated], extra_filter_class=[])
def dept_lazy_tree(self, request, *args, **kwargs):
parent = self.request.query_params.get('parent')
is_superuser = request.user.is_superuser
if is_superuser:
queryset = Dept.objects.values('id', 'name', 'parent')
else:
role_ids = request.user.role.values_list('id',flat=True)
data_range = RoleMenuButtonPermission.objects.filter(role__in=role_ids).values_list('data_range', flat=True)
user_dept_id = request.user.dept.id
dept_list = [user_dept_id]
data_range_list = list(set(data_range))
for item in data_range_list:
if item in [0,2]:
dept_list = [user_dept_id]
elif item == 1:
dept_list = Dept.recursion_dept_info(dept_id=user_dept_id)
elif item == 3:
dept_list = Dept.objects.values_list('id',flat=True)
elif item == 4:
dept_list = request.user.role.values_list('dept',flat=True)
else:
dept_list = []
queryset = Dept.objects.filter(id__in=dept_list).values('id', 'name', 'parent')
return DetailResponse(data=queryset, msg="获取成功")
@action(methods=["GET"], detail=False, permission_classes=[IsAuthenticated],extra_filter_class=[])
def all_dept(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
data = queryset.filter(status=True).order_by('sort').values('name', 'id', 'parent')
return DetailResponse(data=data, msg="获取成功")

View File

@@ -0,0 +1,107 @@
# -*- coding: utf-8 -*-
"""
@author: 猿小天
@contact: QQ:1638245306
@Created on: 2021/6/3 003 0:30
@Remark: 字典管理
"""
from rest_framework import serializers
from rest_framework.views import APIView
from application import dispatch
from dvadmin.system.models import Dictionary
from dvadmin.utils.json_response import SuccessResponse
from dvadmin.utils.serializers import CustomModelSerializer
from dvadmin.utils.viewset import CustomModelViewSet
class DictionarySerializer(CustomModelSerializer):
"""
字典-序列化器
"""
class Meta:
model = Dictionary
fields = "__all__"
read_only_fields = ["id"]
class DictionaryCreateUpdateSerializer(CustomModelSerializer):
"""
字典管理 创建/更新时的列化器
"""
value = serializers.CharField(max_length=100)
def validate_value(self, value):
"""
在父级的字典编号验证重复性
"""
initial_data = self.initial_data
parent = initial_data.get('parent',None)
if parent is None:
unique = Dictionary.objects.filter(value=value).exists()
if unique:
raise serializers.ValidationError("字典编号不能重复")
return value
class Meta:
model = Dictionary
fields = '__all__'
class DictionaryViewSet(CustomModelViewSet):
"""
字典管理接口
list:查询
create:新增
update:修改
retrieve:单例
destroy:删除
"""
queryset = Dictionary.objects.all()
serializer_class = DictionarySerializer
create_serializer_class = DictionaryCreateUpdateSerializer
extra_filter_class = []
search_fields = ['label']
def get_queryset(self):
if self.action =='list':
params = self.request.query_params
parent = params.get('parent', None)
if params:
if parent:
queryset = self.queryset.filter(parent=parent)
else:
queryset = self.queryset.filter(parent__isnull=True)
else:
queryset = self.queryset.filter(parent__isnull=True)
return queryset
else:
return self.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')
if dictionary_key:
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')
return SuccessResponse(data=data, msg="获取成功")
return SuccessResponse(data=[], msg="获取成功")

View File

@@ -0,0 +1,79 @@
import hashlib
import mimetypes
from rest_framework import serializers
from rest_framework.decorators import action
from application import dispatch
from dvadmin.system.models import FileList
from dvadmin.utils.json_response import DetailResponse
from dvadmin.utils.serializers import CustomModelSerializer
from dvadmin.utils.viewset import CustomModelViewSet
class FileSerializer(CustomModelSerializer):
url = serializers.SerializerMethodField(read_only=True)
def get_url(self, instance):
# return 'media/' + str(instance.url)
return instance.file_url or (f'media/{str(instance.url)}')
class Meta:
model = FileList
fields = "__all__"
def create(self, validated_data):
file_engine = dispatch.get_system_config_values("fileStorageConfig.file_engine") or 'local'
file_backup = dispatch.get_system_config_values("fileStorageConfig.file_backup")
file = self.initial_data.get('file')
file_size = file.size
validated_data['name'] = str(file)
validated_data['size'] = file_size
md5 = hashlib.md5()
for chunk in file.chunks():
md5.update(chunk)
validated_data['md5sum'] = md5.hexdigest()
validated_data['engine'] = file_engine
validated_data['mime_type'] = file.content_type
if file_backup:
validated_data['url'] = file
if file_engine == 'oss':
from dvadmin_cloud_storage.views.aliyun import ali_oss_upload
file_path = ali_oss_upload(file)
if file_path:
validated_data['file_url'] = file_path
else:
raise ValueError("上传失败")
elif file_engine == 'cos':
from dvadmin_cloud_storage.views.tencent import tencent_cos_upload
file_path = tencent_cos_upload(file)
if file_path:
validated_data['file_url'] = file_path
else:
raise ValueError("上传失败")
else:
validated_data['url'] = file
# 审计字段
try:
request_user = self.request.user
validated_data['dept_belong_id'] = request_user.dept.id
validated_data['creator'] = request_user.id
validated_data['modifier'] = request_user.id
except:
pass
return super().create(validated_data)
class FileViewSet(CustomModelViewSet):
"""
文件管理接口
list:查询
create:新增
update:修改
retrieve:单例
destroy:删除
"""
queryset = FileList.objects.all()
serializer_class = FileSerializer
filter_fields = ['name', ]
permission_classes = []

View File

@@ -0,0 +1,251 @@
import base64
import hashlib
from datetime import datetime, timedelta
from captcha.views import CaptchaStore, captcha_image
from django.contrib import auth
from django.contrib.auth import login
from django.shortcuts import redirect
from django.utils.translation import gettext_lazy as _
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework import serializers
from rest_framework.views import APIView
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.views import TokenObtainPairView
from django.conf import settings
from application import dispatch
from dvadmin.system.models import Users
from dvadmin.utils.json_response import ErrorResponse, DetailResponse
from dvadmin.utils.request_util import save_login_log
from dvadmin.utils.serializers import CustomModelSerializer
from dvadmin.utils.validator import CustomValidationError
class CaptchaView(APIView):
authentication_classes = []
permission_classes = []
@swagger_auto_schema(
responses={"200": openapi.Response("获取成功")},
security=[],
operation_id="captcha-get",
operation_description="验证码获取",
)
def get(self, request):
data = {}
if dispatch.get_system_config_values("base.captcha_state"):
hashkey = CaptchaStore.generate_key()
id = CaptchaStore.objects.filter(hashkey=hashkey).first().id
imgage = captcha_image(request, hashkey)
# 将图片转换为base64
image_base = base64.b64encode(imgage.content)
data = {
"key": id,
"image_base": "data:image/png;base64," + image_base.decode("utf-8"),
}
return DetailResponse(data=data)
class LoginSerializer(TokenObtainPairSerializer):
"""
登录的序列化器:
重写djangorestframework-simplejwt的序列化器
"""
captcha = serializers.CharField(
max_length=6, required=False, allow_null=True, allow_blank=True
)
class Meta:
model = Users
fields = "__all__"
read_only_fields = ["id"]
default_error_messages = {"no_active_account": _("账号/密码错误")}
def validate(self, attrs):
captcha = self.initial_data.get("captcha", None)
if dispatch.get_system_config_values("base.captcha_state"):
if captcha is None:
raise CustomValidationError("验证码不能为空")
self.image_code = CaptchaStore.objects.filter(
id=self.initial_data["captchaKey"]
).first()
five_minute_ago = datetime.now() - timedelta(hours=0, minutes=5, seconds=0)
if self.image_code and five_minute_ago > self.image_code.expiration:
self.image_code and self.image_code.delete()
raise CustomValidationError("验证码过期")
else:
if self.image_code and (
self.image_code.response == captcha
or self.image_code.challenge == captcha
):
self.image_code and self.image_code.delete()
else:
self.image_code and self.image_code.delete()
raise CustomValidationError("图片验证码错误")
user = Users.objects.get(username=attrs['username'])
if not user.is_active:
raise CustomValidationError("账号被锁定")
data = super().validate(attrs)
data["name"] = self.user.name
data["userId"] = self.user.id
data["avatar"] = self.user.avatar
data['user_type'] = self.user.user_type
dept = getattr(self.user, 'dept', None)
if dept:
data['dept_info'] = {
'dept_id': dept.id,
'dept_name': dept.name,
}
role = getattr(self.user, 'role', None)
if role:
data['role_info'] = role.values('id', 'name', 'key')
request = self.context.get("request")
request.user = self.user
# 记录登录日志
save_login_log(request=request)
return {"code": 2000, "msg": "请求成功", "data": data}
class LoginView(TokenObtainPairView):
"""
登录接口
"""
serializer_class = LoginSerializer
permission_classes = []
# def post(self, request, *args, **kwargs):
# # username可能携带的不止是用户名可能还是用户的其它唯一标识 手机号 邮箱
# username = request.data.get('username',None)
# if username is None:
# return ErrorResponse(msg="参数错误")
# password = request.data.get('password',None)
# if password is None:
# return ErrorResponse(msg="参数错误")
# captcha = request.data.get('captcha',None)
# if captcha is None:
# return ErrorResponse(msg="参数错误")
# captchaKey = request.data.get('captchaKey',None)
# if captchaKey is None:
# return ErrorResponse(msg="参数错误")
# if dispatch.get_system_config_values("base.captcha_state"):
# if captcha is None:
# raise CustomValidationError("验证码不能为空")
# self.image_code = CaptchaStore.objects.filter(
# id=captchaKey
# ).first()
# five_minute_ago = datetime.now() - timedelta(hours=0, minutes=5, seconds=0)
# if self.image_code and five_minute_ago > self.image_code.expiration:
# self.image_code and self.image_code.delete()
# raise CustomValidationError("验证码过期")
# else:
# if self.image_code and (
# self.image_code.response == captcha
# or self.image_code.challenge == captcha
# ):
# self.image_code and self.image_code.delete()
# else:
# self.image_code and self.image_code.delete()
# raise CustomValidationError("图片验证码错误")
# try:
# # 手动通过 user 签发 jwt-token
# user = Users.objects.get(username=username)
# except:
# return DetailResponse(msg='该账号未注册')
# # 获得用户后校验密码并签发token
# print(make_password(password),user.password)
# if check_password(make_password(password),user.password):
# return DetailResponse(msg='密码错误')
# result = {
# "name":user.name,
# "userId":user.id,
# "avatar":user.avatar,
# }
# dept = getattr(user, 'dept', None)
# if dept:
# result['dept_info'] = {
# 'dept_id': dept.id,
# 'dept_name': dept.name,
# 'dept_key': dept.key
# }
# role = getattr(user, 'role', None)
# if role:
# result['role_info'] = role.values('id', 'name', 'key')
# refresh = LoginSerializer.get_token(user)
# result["refresh"] = str(refresh)
# result["access"] = str(refresh.access_token)
# # 记录登录日志
# request.user = user
# save_login_log(request=request)
# return DetailResponse(data=result,msg="获取成功")
class LoginTokenSerializer(TokenObtainPairSerializer):
"""
登录的序列化器:
"""
class Meta:
model = Users
fields = "__all__"
read_only_fields = ["id"]
default_error_messages = {"no_active_account": _("账号/密码不正确")}
def validate(self, attrs):
if not getattr(settings, "LOGIN_NO_CAPTCHA_AUTH", False):
return {"code": 4000, "msg": "该接口暂未开通!", "data": None}
data = super().validate(attrs)
data["name"] = self.user.name
data["userId"] = self.user.id
return {"code": 2000, "msg": "请求成功", "data": data}
class LoginTokenView(TokenObtainPairView):
"""
登录获取token接口
"""
serializer_class = LoginTokenSerializer
permission_classes = []
class LogoutView(APIView):
def post(self, request):
return DetailResponse(msg="注销成功")
class ApiLoginSerializer(CustomModelSerializer):
"""接口文档登录-序列化器"""
username = serializers.CharField()
password = serializers.CharField()
class Meta:
model = Users
fields = ["username", "password"]
class ApiLogin(APIView):
"""接口文档的登录接口"""
serializer_class = ApiLoginSerializer
authentication_classes = []
permission_classes = []
def post(self, request):
username = request.data.get("username")
password = request.data.get("password")
user_obj = auth.authenticate(
request,
username=username,
password=hashlib.md5(password.encode(encoding="UTF-8")).hexdigest(),
)
if user_obj:
login(request, user_obj)
return redirect("/")
else:
return ErrorResponse(msg="账号/密码错误")

View File

@@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
"""
@author: 猿小天
@contact: QQ:1638245306
@Created on: 2021/6/3 003 0:30
@Remark: 按钮权限管理
"""
from dvadmin.system.models import LoginLog
from dvadmin.utils.serializers import CustomModelSerializer
from dvadmin.utils.viewset import CustomModelViewSet
class LoginLogSerializer(CustomModelSerializer):
"""
登录日志权限-序列化器
"""
class Meta:
model = LoginLog
fields = "__all__"
read_only_fields = ["id"]
class LoginLogViewSet(CustomModelViewSet):
"""
登录日志接口
list:查询
create:新增
update:修改
retrieve:单例
destroy:删除
"""
queryset = LoginLog.objects.all()
serializer_class = LoginLogSerializer
extra_filter_class = []

View File

@@ -0,0 +1,152 @@
# -*- coding: utf-8 -*-
"""
@author: 猿小天
@contact: QQ:1638245306
@Created on: 2021/6/1 001 22:38
@Remark: 菜单模块
"""
from rest_framework import serializers
from rest_framework.decorators import action
from dvadmin.system.models import Menu, MenuButton, RoleMenuPermission
from dvadmin.utils.json_response import SuccessResponse
from dvadmin.utils.serializers import CustomModelSerializer
from dvadmin.utils.viewset import CustomModelViewSet
class MenuSerializer(CustomModelSerializer):
"""
菜单表的简单序列化器
"""
menuPermission = serializers.SerializerMethodField(read_only=True)
hasChild = serializers.SerializerMethodField()
def get_menuPermission(self, instance):
queryset = instance.menuPermission.order_by('-name').values_list('name', flat=True)
if queryset:
return queryset
else:
return None
def get_hasChild(self, instance):
hasChild = Menu.objects.filter(parent=instance.id)
if hasChild:
return True
return False
class Meta:
model = Menu
fields = "__all__"
read_only_fields = ["id"]
class MenuCreateSerializer(CustomModelSerializer):
"""
菜单表的创建序列化器
"""
name = serializers.CharField(required=False)
class Meta:
model = Menu
fields = "__all__"
read_only_fields = ["id"]
class WebRouterSerializer(CustomModelSerializer):
"""
前端菜单路由的简单序列化器
"""
path = serializers.CharField(source="web_path")
title = serializers.CharField(source="name")
class Meta:
model = Menu
fields = (
'id', 'parent', 'icon', 'sort', 'path', 'name', 'title', 'is_link', 'is_catalog', 'web_path', 'component',
'component_name', 'cache', 'visible', 'status')
read_only_fields = ["id"]
class MenuViewSet(CustomModelViewSet):
"""
菜单管理接口
list:查询
create:新增
update:修改
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']
# extra_filter_class = []
@action(methods=['GET'], detail=False, permission_classes=[])
def web_router(self, request):
"""用于前端获取当前角色的路由"""
user = request.user
is_admin = user.role.values_list('admin', flat=True)
if user.is_superuser or True in is_admin:
queryset = self.queryset.filter(status=1)
else:
role_list = user.role.values_list('id', flat=True)
menu_list = RoleMenuPermission.objects.filter(role__in=role_list).values_list('menu_id',flat=True)
print("role_list", role_list)
print("menu_list",menu_list)
queryset = Menu.objects.filter(id__in=menu_list)
print(queryset)
serializer = WebRouterSerializer(queryset, many=True, request=request)
data = serializer.data
return SuccessResponse(data=data, total=len(data), msg="获取成功")
@action(methods=['GET'], detail=False, permission_classes=[])
def get_all_menu(self, request):
"""用于菜单管理获取所有的菜单"""
user = request.user
queryset = self.queryset.all()
if not user.is_superuser:
role_list = user.role.values_list('id', flat=True)
menu_list = RoleMenuPermission.objects.filter(role__in=role_list).values_list('menu_id')
queryset = Menu.objects.filter(id__in=menu_list)
serializer = WebRouterSerializer(queryset, many=True, request=request)
data = serializer.data
return SuccessResponse(data=data, total=len(data), msg="获取成功")
@action(methods=['POST'], detail=False, permission_classes=[])
def drag_menu(self, request):
"""前端拖拽菜单之后重写parent"""
menu_id = request.data['menu_id']
parent_id = request.data['parent_id']
menu = Menu.objects.get(id=menu_id)
menu.parent_id = parent_id
menu.save()
return SuccessResponse(data=[], msg="拖拽菜单成功")
def list(self, request):
"""懒加载"""
request.query_params._mutable = True
params = request.query_params
parent = params.get('parent', None)
page = params.get('page', None)
limit = params.get('limit', None)
if page:
del params['page']
if limit:
del params['limit']
if params:
if parent:
queryset = self.queryset.filter(parent=parent)
else:
queryset = self.queryset.filter()
else:
queryset = self.queryset.filter(parent__isnull=True)
queryset = self.filter_queryset(queryset)
serializer = MenuSerializer(queryset, many=True, request=request)
data = serializer.data
return SuccessResponse(data=data)

View File

@@ -0,0 +1,72 @@
# -*- coding: utf-8 -*-
"""
@author: 猿小天
@contact: QQ:1638245306
@Created on: 2021/6/3 003 0:30
@Remark: 菜单按钮管理
"""
from django.db.models import F
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from dvadmin.system.models import MenuButton, RoleMenuButtonPermission
from dvadmin.utils.json_response import DetailResponse
from dvadmin.utils.serializers import CustomModelSerializer
from dvadmin.utils.viewset import CustomModelViewSet
class MenuButtonSerializer(CustomModelSerializer):
"""
菜单按钮-序列化器
"""
class Meta:
model = MenuButton
fields = ['id', 'name', 'value', 'api', 'method','menu']
read_only_fields = ["id"]
class MenuButtonCreateUpdateSerializer(CustomModelSerializer):
"""
初始化菜单按钮-序列化器
"""
class Meta:
model = MenuButton
fields = "__all__"
read_only_fields = ["id"]
class MenuButtonViewSet(CustomModelViewSet):
"""
菜单按钮接口
list:查询
create:新增
update:修改
retrieve:单例
destroy:删除
"""
queryset = MenuButton.objects.all()
serializer_class = MenuButtonSerializer
create_serializer_class = MenuButtonCreateUpdateSerializer
update_serializer_class = MenuButtonCreateUpdateSerializer
extra_filter_class = []
@action(methods=['get'],detail=False,permission_classes=[IsAuthenticated])
def menu_button_all_permission(self,request):
"""
获取所有的按钮权限
:param request:
:return:
"""
is_superuser = request.user.is_superuser
is_admin = request.user.role.values_list('admin', flat=True)
if is_superuser or True in is_admin:
queryset = MenuButton.objects.values_list('value',flat=True)
else:
role_id = request.user.role.values_list('id', flat=True)
queryset = RoleMenuButtonPermission.objects.filter(role__in=role_id).values_list('menu_button__value',flat=True).distinct()
return DetailResponse(data=queryset)

View File

@@ -0,0 +1,218 @@
# -*- coding: utf-8 -*-
import json
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
from django_restql.fields import DynamicSerializerMethodField
from rest_framework import serializers
from rest_framework.decorators import action, permission_classes
from rest_framework.permissions import IsAuthenticated, AllowAny
from dvadmin.system.models import MessageCenter, Users, MessageCenterTargetUser
from dvadmin.utils.json_response import SuccessResponse, DetailResponse
from dvadmin.utils.serializers import CustomModelSerializer
from dvadmin.utils.viewset import CustomModelViewSet
class MessageCenterSerializer(CustomModelSerializer):
"""
消息中心-序列化器
"""
role_info = DynamicSerializerMethodField()
user_info = DynamicSerializerMethodField()
dept_info = DynamicSerializerMethodField()
is_read = serializers.BooleanField(read_only=True, source='target_user__is_read')
def get_role_info(self, instance, parsed_query):
roles = instance.target_role.all()
# You can do what ever you want in here
# `parsed_query` param is passed to BookSerializer to allow further querying
from dvadmin.system.views.role import RoleSerializer
serializer = RoleSerializer(
roles,
many=True,
parsed_query=parsed_query
)
return serializer.data
def get_user_info(self, instance, parsed_query):
users = instance.target_user.all()
# You can do what ever you want in here
# `parsed_query` param is passed to BookSerializer to allow further querying
from dvadmin.system.views.user import UserSerializer
serializer = UserSerializer(
users,
many=True,
parsed_query=parsed_query
)
return serializer.data
def get_dept_info(self, instance, parsed_query):
dept = instance.target_dept.all()
# You can do what ever you want in here
# `parsed_query` param is passed to BookSerializer to allow further querying
from dvadmin.system.views.dept import DeptSerializer
serializer = DeptSerializer(
dept,
many=True,
parsed_query=parsed_query
)
return serializer.data
class Meta:
model = MessageCenter
fields = "__all__"
read_only_fields = ["id"]
class MessageCenterTargetUserSerializer(CustomModelSerializer):
"""
目标用户序列化器-序列化器
"""
class Meta:
model = MessageCenterTargetUser
fields = "__all__"
read_only_fields = ["id"]
class MessageCenterTargetUserListSerializer(CustomModelSerializer):
"""
目标用户序列化器-序列化器
"""
is_read = serializers.SerializerMethodField()
def get_is_read(self, instance):
user_id = self.request.user.id
message_center_id = instance.id
queryset = MessageCenterTargetUser.objects.filter(messagecenter__id=message_center_id, users_id=user_id).first()
if queryset:
return queryset.is_read
return False
class Meta:
model = MessageCenter
fields = "__all__"
read_only_fields = ["id"]
def websocket_push(user_id, message):
"""
主动推送消息
"""
username = "user_" + str(user_id)
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(
username,
{
"type": "push.message",
"json": message
}
)
class MessageCenterCreateSerializer(CustomModelSerializer):
"""
消息中心-新增-序列化器
"""
def save(self, **kwargs):
data = super().save(**kwargs)
initial_data = self.initial_data
target_type = initial_data.get('target_type')
# 在保存之前,根据目标类型,把目标用户查询出来并保存
users = initial_data.get('target_user', [])
if target_type in [1]: # 按角色
target_role = initial_data.get('target_role', [])
users = Users.objects.filter(role__id__in=target_role).values_list('id', flat=True)
if target_type in [2]: # 按部门
target_dept = initial_data.get('target_dept', [])
users = Users.objects.filter(dept__id__in=target_dept).values_list('id', flat=True)
if target_type in [3]: # 系统通知
users = Users.objects.values_list('id', flat=True)
targetuser_data = []
for user in users:
targetuser_data.append({
"messagecenter": data.id,
"users": user
})
targetuser_instance = MessageCenterTargetUserSerializer(data=targetuser_data, many=True, request=self.request)
targetuser_instance.is_valid(raise_exception=True)
targetuser_instance.save()
for user in users:
unread_count = MessageCenterTargetUser.objects.filter(users__id=user, is_read=False).count()
websocket_push(user, message={"sender": 'system', "contentType": 'SYSTEM',
"content": '您有一条新消息~', "unread": unread_count})
return data
class Meta:
model = MessageCenter
fields = "__all__"
read_only_fields = ["id"]
class MessageCenterViewSet(CustomModelViewSet):
"""
消息中心接口
list:查询
create:新增
update:修改
retrieve:单例
destroy:删除
"""
queryset = MessageCenter.objects.order_by('create_datetime')
serializer_class = MessageCenterSerializer
create_serializer_class = MessageCenterCreateSerializer
extra_filter_backends = []
def get_queryset(self):
if self.action == 'list':
return MessageCenter.objects.filter(creator=self.request.user.id).all()
return MessageCenter.objects.all()
def retrieve(self, request, *args, **kwargs):
"""
重写查看
"""
pk = kwargs.get('pk')
user_id = self.request.user.id
queryset = MessageCenterTargetUser.objects.filter(users__id=user_id, messagecenter__id=pk).first()
if queryset:
queryset.is_read = True
queryset.save()
instance = self.get_object()
serializer = self.get_serializer(instance)
# 主动推送消息
unread_count = MessageCenterTargetUser.objects.filter(users__id=user_id, is_read=False).count()
websocket_push(user_id, message={"sender": 'system', "contentType": 'TEXT',
"content": '您查看了一条消息~', "unread": unread_count})
return DetailResponse(data=serializer.data, msg="获取成功")
@action(methods=['GET'], detail=False, permission_classes=[IsAuthenticated])
def get_self_receive(self, request):
"""
获取接收到的消息
"""
self_user_id = self.request.user.id
# queryset = MessageCenterTargetUser.objects.filter(users__id=self_user_id).order_by('-create_datetime')
queryset = MessageCenter.objects.filter(target_user__id=self_user_id)
# queryset = self.filter_queryset(queryset)
page = self.paginate_queryset(queryset)
if page is not None:
serializer = MessageCenterTargetUserListSerializer(page, many=True, request=request)
return self.get_paginated_response(serializer.data)
serializer = MessageCenterTargetUserListSerializer(queryset, many=True, request=request)
return SuccessResponse(data=serializer.data, msg="获取成功")
@action(methods=['GET'], detail=False, permission_classes=[IsAuthenticated])
def get_newest_msg(self, request):
"""
获取最新的一条消息
"""
self_user_id = self.request.user.id
queryset = MessageCenterTargetUser.objects.filter(users__id=self_user_id).order_by('create_datetime').last()
data = None
if queryset:
serializer = MessageCenterTargetUserListSerializer(queryset.messagecenter, many=False, request=request)
data = serializer.data
return DetailResponse(data=data, msg="获取成功")

View File

@@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
"""
@author: 李强
@contact: QQ:1206709430
@Created on: 2021/6/8 003 0:30
@Remark: 操作日志管理
"""
from dvadmin.system.models import OperationLog
from dvadmin.utils.serializers import CustomModelSerializer
from dvadmin.utils.viewset import CustomModelViewSet
class OperationLogSerializer(CustomModelSerializer):
"""
日志-序列化器
"""
class Meta:
model = OperationLog
fields = "__all__"
read_only_fields = ["id"]
class OperationLogCreateUpdateSerializer(CustomModelSerializer):
"""
操作日志 创建/更新时的列化器
"""
class Meta:
model = OperationLog
fields = '__all__'
class OperationLogViewSet(CustomModelViewSet):
"""
操作日志接口
list:查询
create:新增
update:修改
retrieve:单例
destroy:删除
"""
queryset = OperationLog.objects.order_by('-create_datetime')
serializer_class = OperationLogSerializer
# permission_classes = []

View File

@@ -0,0 +1,98 @@
# -*- coding: utf-8 -*-
"""
@author: 猿小天
@contact: QQ:1638245306
@Created on: 2021/6/3 003 0:30
@Remark: 角色管理
"""
from rest_framework import serializers
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from dvadmin.system.models import Role, Menu, MenuButton, Dept
from dvadmin.system.views.dept import DeptSerializer
from dvadmin.system.views.menu import MenuSerializer
from dvadmin.system.views.menu_button import MenuButtonSerializer
from dvadmin.utils.crud_mixin import FastCrudMixin
from dvadmin.utils.json_response import SuccessResponse, DetailResponse
from dvadmin.utils.serializers import CustomModelSerializer
from dvadmin.utils.validator import CustomUniqueValidator
from dvadmin.utils.viewset import CustomModelViewSet
class RoleSerializer(CustomModelSerializer):
"""
角色-序列化器
"""
class Meta:
model = Role
fields = "__all__"
read_only_fields = ["id"]
class RoleCreateUpdateSerializer(CustomModelSerializer):
"""
角色管理 创建/更新时的列化器
"""
menu = MenuSerializer(many=True, read_only=True)
dept = DeptSerializer(many=True, read_only=True)
permission = MenuButtonSerializer(many=True, read_only=True)
key = serializers.CharField(max_length=50,
validators=[CustomUniqueValidator(queryset=Role.objects.all(), message="权限字符必须唯一")])
name = serializers.CharField(max_length=50, validators=[CustomUniqueValidator(queryset=Role.objects.all())])
def validate(self, attrs: dict):
return super().validate(attrs)
def save(self, **kwargs):
is_superuser = self.request.user.is_superuser
if not is_superuser:
self.validated_data.pop('admin')
data = super().save(**kwargs)
return data
class Meta:
model = Role
fields = '__all__'
class MenuPermissonSerializer(CustomModelSerializer):
"""
菜单的按钮权限
"""
menuPermission = serializers.SerializerMethodField()
def get_menuPermission(self, instance):
is_superuser = self.request.user.is_superuser
if is_superuser:
queryset = MenuButton.objects.filter(menu__id=instance.id)
else:
menu_permission_id_list = self.request.user.role.values_list('permission',flat=True)
queryset = MenuButton.objects.filter(id__in=menu_permission_id_list,menu__id=instance.id)
serializer = MenuButtonSerializer(queryset,many=True, read_only=True)
return serializer.data
class Meta:
model = Menu
fields = ['id', 'parent', 'name', 'menuPermission']
class RoleViewSet(CustomModelViewSet,FastCrudMixin):
"""
角色管理接口
list:查询
create:新增
update:修改
retrieve:单例
destroy:删除
"""
queryset = Role.objects.all()
serializer_class = RoleSerializer
create_serializer_class = RoleCreateUpdateSerializer
update_serializer_class = RoleCreateUpdateSerializer
search_fields = ['name', 'key']

View File

@@ -0,0 +1,86 @@
# -*- coding: utf-8 -*-
from django.db.models import F
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from dvadmin.system.models import RoleMenuPermission, Menu, MenuButton
from dvadmin.utils.json_response import DetailResponse, ErrorResponse
from dvadmin.utils.serializers import CustomModelSerializer
from dvadmin.utils.viewset import CustomModelViewSet
class RoleMenuPermissionSerializer(CustomModelSerializer):
"""
菜单按钮-序列化器
"""
class Meta:
model = RoleMenuPermission
fields = "__all__"
read_only_fields = ["id"]
class RoleMenuPermissionInitSerializer(CustomModelSerializer):
"""
初始化菜单按钮-序列化器
"""
class Meta:
model = RoleMenuPermission
fields = "__all__"
read_only_fields = ["id"]
class RoleMenuPermissionCreateUpdateSerializer(CustomModelSerializer):
"""
初始化菜单按钮-序列化器
"""
class Meta:
model = RoleMenuPermission
fields = "__all__"
read_only_fields = ["id"]
class RoleMenuPermissionViewSet(CustomModelViewSet):
"""
菜单按钮接口
list:查询
create:新增
update:修改
retrieve:单例
destroy:删除
"""
queryset = RoleMenuPermission.objects.all()
serializer_class = RoleMenuPermissionSerializer
create_serializer_class = RoleMenuPermissionCreateUpdateSerializer
update_serializer_class = RoleMenuPermissionCreateUpdateSerializer
extra_filter_class = []
@action(methods=['post'],detail=False)
def save_auth(self,request):
"""
保存页面菜单授权
:param request:
:return:
"""
body = request.data
role_id = body.get('role',None)
if role_id is None:
return ErrorResponse(msg="未获取到角色参数")
menu_list = body.get('menu',None)
if menu_list is None:
return ErrorResponse(msg="未获取到菜单参数")
obj_list = RoleMenuPermission.objects.filter(role__id=role_id).values_list('menu__id',flat=True)
old_set = set(obj_list)
new_set = set(menu_list)
#need_update = old_set.intersection(new_set) # 需要更新的
need_del = old_set.difference(new_set) # 需要删除的
need_add = new_set.difference(old_set) # 需要新增的
RoleMenuPermission.objects.filter(role__id=role_id,menu__in=list(need_del)).delete()
data = [{"role": role_id, "menu": item} for item in list(need_add)]
serializer = RoleMenuPermissionSerializer(data=data,many=True,request=request)
if serializer.is_valid(raise_exception=True):
serializer.save()
return DetailResponse(msg="保存成功",data=serializer.data)

View File

@@ -0,0 +1,280 @@
# -*- coding: utf-8 -*-
"""
@author: 猿小天
@contact: QQ:1638245306
@Created on: 2021/6/3 003 0:30
@Remark: 菜单按钮管理
"""
from django.db.models import F, Subquery, OuterRef, Exists
from rest_framework import serializers
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from dvadmin.system.models import RoleMenuButtonPermission, Menu, MenuButton, Dept, RoleMenuPermission
from dvadmin.utils.json_response import DetailResponse, ErrorResponse
from dvadmin.utils.serializers import CustomModelSerializer
from dvadmin.utils.viewset import CustomModelViewSet
class RoleMenuButtonPermissionSerializer(CustomModelSerializer):
"""
菜单按钮-序列化器
"""
class Meta:
model = RoleMenuButtonPermission
fields = "__all__"
read_only_fields = ["id"]
class RoleMenuButtonPermissionInitSerializer(CustomModelSerializer):
"""
初始化菜单按钮-序列化器
"""
class Meta:
model = RoleMenuButtonPermission
fields = "__all__"
read_only_fields = ["id"]
class RoleMenuButtonPermissionCreateUpdateSerializer(CustomModelSerializer):
"""
初始化菜单按钮-序列化器
"""
menu_button__name = serializers.CharField(source='menu_button.name', read_only=True)
menu_button__value= serializers.CharField(source='menu_button.value', read_only=True)
class Meta:
model = RoleMenuButtonPermission
fields = "__all__"
read_only_fields = ["id"]
class RoleMenuButtonPermissionViewSet(CustomModelViewSet):
"""
菜单按钮接口
list:查询
create:新增
update:修改
retrieve:单例
destroy:删除
"""
queryset = RoleMenuButtonPermission.objects.all()
serializer_class = RoleMenuButtonPermissionSerializer
create_serializer_class = RoleMenuButtonPermissionCreateUpdateSerializer
update_serializer_class = RoleMenuButtonPermissionCreateUpdateSerializer
extra_filter_class = []
@action(methods=['GET'], detail=False, permission_classes=[IsAuthenticated])
def role_get_menu(self, request):
"""根据当前用户的角色返回角色拥有的菜单"""
data = []
is_superuser = request.user.is_superuser
is_admin = request.user.role.values_list('admin', flat=True)
if is_superuser or True in is_admin:
queryset = Menu.objects.filter(status=1).values('name','parent','is_catalog',menu_id=F('id'))
for item in queryset:
btn_name = MenuButton.objects.filter(menu=item['menu_id']).values_list(
'name', flat=True)
data.append({'menu_id': item['menu_id'], 'name': item['name'], 'parent': item['parent'],
'permission': ','.join(btn_name), 'is_catalog': item['is_catalog']})
else:
role_id = request.user.role.values_list('id',flat=True)
queryset = RoleMenuPermission.objects.filter(role__in=role_id).values('menu_id',name=F('menu__name'),parent=F('menu__parent'),is_catalog=F('menu__is_catalog')).distinct()
for item in queryset:
btn_name = RoleMenuButtonPermission.objects.filter(menu_button__menu=item['menu_id']).values_list('menu_button__name',flat=True)
data.append({'menu_id':item['menu_id'], 'name':item['name'], 'parent':item['parent'],'permission':','.join(btn_name),'is_catalog':item['is_catalog']})
return DetailResponse(data=data)
@action(methods=['GET'], detail=False, permission_classes=[IsAuthenticated])
def role_menu_get_button(self,request):
"""
当前用户角色和菜单获取可下拉选项的按钮:角色授权页面使用
:param request:
:return:
"""
if params := request.query_params:
if menu_id := params.get('menu', None):
is_superuser = request.user.is_superuser
is_admin = request.user.role.values_list('admin', flat=True)
if is_superuser or True in is_admin:
queryset = MenuButton.objects.filter(menu=menu_id).values('id', 'name')
else:
role_list = request.user.role.values_list('id',flat=True)
queryset = RoleMenuButtonPermission.objects.filter(role__in=role_list,menu_button__menu=menu_id).values(
btn_id=F('menu_button__id'),
name=F('menu_button__name')
)
return DetailResponse(data=queryset)
return ErrorResponse(msg="参数错误")
@action(methods=['GET'], detail=False, permission_classes=[IsAuthenticated])
def data_scope(self, request):
"""
获取数据权限范围:角色授权页面使用
:param request:
:return:
"""
is_superuser = request.user.is_superuser
if is_superuser:
data = [
{
"value": 0,
"label": '仅本人数据权限'
},
{
"value": 1,
"label": '本部门及以下数据权限'
},
{
"value": 2,
"label": '本部门数据权限'
},
{
"value": 3,
"label": '全部数据权限'
},
{
"value": 4,
"label": '自定义数据权限'
}
]
return DetailResponse(data=data)
else:
data = []
role_list = request.user.role.values_list('id',flat=True)
if params := request.query_params:
if menu_button_id := params.get('menu_button', None):
role_queryset = RoleMenuButtonPermission.objects.filter(role__in=role_list,menu_button__id=menu_button_id).values_list('data_range',flat=True)
data_range_list = list(set(role_queryset))
for item in data_range_list:
if item == 0:
data = [{
"value": 0,
"label": '仅本人数据权限'
}]
elif item == 1:
data = [{
"value": 0,
"label": '仅本人数据权限'
}, {
"value": 1,
"label": '本部门及以下数据权限'
},
{
"value": 2,
"label": '本部门数据权限'
}]
elif item == 2:
data = [{
"value": 0,
"label": '仅本人数据权限'
},
{
"value": 2,
"label": '本部门数据权限'
}]
elif item == 3:
data = [{
"value": 0,
"label": '仅本人数据权限'
},
{
"value": 3,
"label": '全部数据权限'
}, ]
elif item == 4:
data = [{
"value": 0,
"label": '仅本人数据权限'
},
{
"value": 4,
"label": '自定义数据权限'
}]
else:
data = []
return DetailResponse(data=data)
return ErrorResponse(msg="参数错误")
@action(methods=['get'], detail=False, permission_classes=[IsAuthenticated])
def role_to_dept_all(self, request):
"""
当前用户角色下所能授权的部门:角色授权页面使用
:param request:
:return:
"""
params = request.query_params
is_superuser = request.user.is_superuser
is_admin = request.user.role.values_list('admin', flat=True)
if is_superuser or True in is_admin:
queryset = Dept.objects.values('id','name','parent')
else:
if not params:
return ErrorResponse(msg="参数错误")
menu_button = params.get('menu_button')
if menu_button is None:
return ErrorResponse(msg="参数错误")
role_list = request.user.role.values_list('id', flat=True)
queryset = RoleMenuButtonPermission.objects.filter(role__in=role_list,menu_button=None).values(
dept_id=F('dept__id'),
name=F('dept__name'),
parent=F('dept__parent')
)
return DetailResponse(data=queryset)
@action(methods=['get'],detail=False,permission_classes=[IsAuthenticated])
def menu_to_button(self,request):
"""
根据所选择菜单获取已配置的按钮/接口权限:角色授权页面使用
:param request:
:return:
"""
params = request.query_params
menu_id = params.get('menu', None)
if menu_id is None:
return ErrorResponse(msg="未获取到参数")
is_superuser = request.user.is_superuser
is_admin = request.user.role.values_list('admin', flat=True)
if is_superuser or True in is_admin:
queryset = RoleMenuButtonPermission.objects.filter(menu_button__menu=menu_id).values(
'id',
'data_range',
'menu_button',
'menu_button__name',
'menu_button__value'
)
return DetailResponse(data=queryset)
else:
if params:
role_id = params.get('role', None)
if role_id is None:
return ErrorResponse(msg="未获取到参数")
queryset = RoleMenuButtonPermission.objects.filter(role=role_id,menu_button__menu=menu_id).values(
'id',
'data_range',
'menu_button',
'menu_button__name',
'menu_button__value'
)
return DetailResponse(data=queryset)
return ErrorResponse(msg="未获取到参数")
@action(methods=['get'], detail=False, permission_classes=[IsAuthenticated])
def role_to_menu(self, request):
"""
获取角色对应的按钮权限
:param request:
:return:
"""
params = request.query_params
role_id = params.get('role', None)
if role_id is None:
return ErrorResponse(msg="未获取到参数")
queryset = RoleMenuPermission.objects.filter(role_id=role_id).values_list('menu_id',flat=True).distinct()
return DetailResponse(data=queryset)

View File

@@ -0,0 +1,234 @@
# -*- coding: utf-8 -*-
"""
@author: 猿小天
@contact: QQ:1638245306
@Created on: 2022/1/21 003 0:30
@Remark: 系统配置
"""
import django_filters
from django.db.models import Q
from django_filters.rest_framework import BooleanFilter
from rest_framework import serializers
from rest_framework.views import APIView
from application import dispatch
from dvadmin.system.models import SystemConfig
from dvadmin.utils.json_response import DetailResponse, SuccessResponse, ErrorResponse
from dvadmin.utils.models import get_all_models_objects
from dvadmin.utils.serializers import CustomModelSerializer
from dvadmin.utils.validator import CustomValidationError
from dvadmin.utils.viewset import CustomModelViewSet
class SystemConfigCreateSerializer(CustomModelSerializer):
"""
系统配置-新增时使用-序列化器
"""
form_item_type_label = serializers.CharField(source='get_form_item_type_display', read_only=True)
class Meta:
model = SystemConfig
fields = "__all__"
read_only_fields = ["id"]
def validate_key(self, value):
"""
验证key是否允许重复
parent为空时不允许重复,反之允许
"""
instance = SystemConfig.objects.filter(key=value, parent__isnull=True).exists()
if instance:
raise CustomValidationError('已存在相同变量名')
return value
class SystemConfigSerializer(CustomModelSerializer):
"""
系统配置-序列化器
"""
form_item_type_label = serializers.CharField(source='get_form_item_type_display', read_only=True)
class Meta:
model = SystemConfig
fields = "__all__"
read_only_fields = ["id"]
class SystemConfigChinldernSerializer(CustomModelSerializer):
"""
系统配置子级-序列化器
"""
children = serializers.SerializerMethodField()
form_item_type_label = serializers.CharField(source='get_form_item_type_display', read_only=True)
def get_children(self, instance):
queryset = SystemConfig.objects.filter(parent=instance)
serializer = SystemConfigSerializer(queryset, many=True)
return serializer.data
class Meta:
model = SystemConfig
fields = "__all__"
read_only_fields = ["id"]
class SystemConfigListSerializer(CustomModelSerializer):
"""
系统配置下模块的保存-序列化器
"""
def update(self, instance, validated_data):
instance_mapping = {obj.id: obj for obj in instance}
data_mapping = {item['id']: item for item in validated_data}
for obj_id, data in data_mapping.items():
instance_obj = instance_mapping.get(obj_id, None)
if instance_obj is None:
return SystemConfig.objects.create(**data)
else:
return instance_obj.objects.update(**data)
class Meta:
model = SystemConfig
fields = "__all__"
read_only_fields = ["id"]
class SystemConfigSaveSerializer(serializers.Serializer):
class Meta:
read_only_fields = ["id"]
list_serializer_class = SystemConfigListSerializer
class SystemConfigFilter(django_filters.rest_framework.FilterSet):
"""
过滤器
"""
parent__isnull = BooleanFilter(field_name='parent', lookup_expr="isnull")
class Meta:
model = SystemConfig
fields = ['id', 'parent', 'status', 'parent__isnull']
class SystemConfigViewSet(CustomModelViewSet):
"""
系统配置接口
"""
queryset = SystemConfig.objects.order_by('sort', 'create_datetime')
serializer_class = SystemConfigChinldernSerializer
create_serializer_class = SystemConfigCreateSerializer
retrieve_serializer_class = SystemConfigChinldernSerializer
# filter_fields = ['id','parent']
filter_class = SystemConfigFilter
def save_content(self, request):
body = request.data
data_mapping = {item['id']: item for item in body}
for obj_id, data in data_mapping.items():
instance_obj = SystemConfig.objects.filter(id=obj_id).first()
if instance_obj is None:
# return SystemConfig.objects.create(**data)
serializer = SystemConfigCreateSerializer(data=data)
else:
serializer = SystemConfigCreateSerializer(instance_obj, data=data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return DetailResponse(msg="保存成功")
def get_association_table(self, request):
"""
获取所有的model及字段信息
"""
res = [ele.get('table') for ele in get_all_models_objects().values()]
return DetailResponse(msg="获取成功", data=res)
def get_table_data(self, request, pk):
"""
动态获取关联表的数据
"""
instance = SystemConfig.objects.filter(id=pk).first()
if instance is None:
return ErrorResponse(msg="查询出错了~")
setting = instance.setting
if setting is None:
return ErrorResponse(msg="查询出错了~")
table = setting.get('table') # 获取model名
model = get_all_models_objects(table).get("object", {})
# 自己判断一下不存在
queryset = model.objects.values()
body = request.query_params
search_value = body.get('search', None)
if search_value:
search_fields = setting.get('searchField')
filters = Q()
filters.connector = 'OR'
for item in search_fields:
filed = '{0}__icontains'.format(item.get('field'))
filters.children.append((filed, search_value))
queryset = model.objects.filter(filters).values()
page = self.paginate_queryset(queryset)
if page is not None:
return self.get_paginated_response(queryset)
return SuccessResponse(msg="获取成功", data=queryset, total=len(queryset))
def get_relation_info(self, request):
"""
查询关联的模板信息
"""
body = request.query_params
var_name = body.get('varName', None)
table = body.get('table', None)
instance = SystemConfig.objects.filter(key=var_name, setting__table=table).first()
if instance is None:
return ErrorResponse(msg="未获取到关联信息")
relation_id = body.get('relationIds', None)
relationIds = []
if relation_id is None:
return ErrorResponse(msg="未获取到关联信息")
if instance.form_item_type in [13]:
relationIds = [relation_id]
elif instance.form_item_type in [14]:
relationIds = relation_id.split(',')
queryset = SystemConfig.objects.filter(value__in=relationIds).first()
if queryset is None:
return ErrorResponse(msg="未获取到关联信息")
serializer = SystemConfigChinldernSerializer(queryset.parent)
return DetailResponse(msg="查询成功", data=serializer.data)
class InitSettingsViewSet(APIView):
"""
获取初始化配置
"""
authentication_classes = []
permission_classes = []
def filter_system_config_values(self, data: dict):
"""
过滤系统初始化配置
:param data:
:return:
"""
if not self.request.query_params.get('key', ''):
return data
new_data = {}
for key in self.request.query_params.get('key', '').split('|'):
if key:
new_data.update(**dict(filter(lambda x: x[0].startswith(key), data.items())))
return new_data
def get(self, request):
data = dispatch.get_system_config()
if not data:
dispatch.refresh_system_config()
data = dispatch.get_system_config()
# 不返回后端专用配置
backend_config = [f"{ele.get('parent__key')}.{ele.get('key')}" for ele in
SystemConfig.objects.filter(status=False, parent_id__isnull=False).values('parent__key',
'key')]
data = dict(filter(lambda x: x[0] not in backend_config, data.items()))
data = self.filter_system_config_values(data=data)
return DetailResponse(data=data)

View File

@@ -0,0 +1,365 @@
import hashlib
from django.contrib.auth.hashers import make_password, check_password
from django_restql.fields import DynamicSerializerMethodField
from rest_framework import serializers
from rest_framework.decorators import action, permission_classes
from rest_framework.permissions import IsAuthenticated
from django.db import connection
from application import dispatch
from dvadmin.system.models import Users, Role, Dept
from dvadmin.system.views.role import RoleSerializer
from dvadmin.utils.json_response import ErrorResponse, DetailResponse
from dvadmin.utils.serializers import CustomModelSerializer
from dvadmin.utils.validator import CustomUniqueValidator
from dvadmin.utils.viewset import CustomModelViewSet
def recursion(instance, parent, result):
new_instance = getattr(instance, parent, None)
res = []
data = getattr(instance, result, None)
if data:
res.append(data)
if new_instance:
array = recursion(new_instance, parent, result)
res += (array)
return res
class UserSerializer(CustomModelSerializer):
"""
用户管理-序列化器
"""
dept_name = serializers.CharField(source='dept.name', read_only=True)
role_info = DynamicSerializerMethodField()
dept_name_all = serializers.SerializerMethodField()
class Meta:
model = Users
read_only_fields = ["id"]
exclude = ["password"]
extra_kwargs = {
"post": {"required": False},
"mobile": {"required": False},
}
def get_dept_name_all(self, instance):
dept_name_all = recursion(instance.dept, "parent", "name")
dept_name_all.reverse()
return "/".join(dept_name_all)
def get_role_info(self, instance, parsed_query):
roles = instance.role.all()
# You can do what ever you want in here
# `parsed_query` param is passed to BookSerializer to allow further querying
serializer = RoleSerializer(
roles,
many=True,
parsed_query=parsed_query
)
return serializer.data
class UserCreateSerializer(CustomModelSerializer):
"""
用户新增-序列化器
"""
username = serializers.CharField(
max_length=50,
validators=[
CustomUniqueValidator(queryset=Users.objects.all(), message="账号必须唯一")
],
)
password = serializers.CharField(
required=False,
)
def validate_password(self, value):
"""
对密码进行验证
"""
md5 = hashlib.md5()
md5.update(value.encode('utf-8'))
md5_password = md5.hexdigest()
return make_password(md5_password)
def save(self, **kwargs):
data = super().save(**kwargs)
data.dept_belong_id = data.dept_id
data.save()
data.post.set(self.initial_data.get("post", []))
return data
class Meta:
model = Users
fields = "__all__"
read_only_fields = ["id"]
extra_kwargs = {
"post": {"required": False},
"mobile": {"required": False},
}
class UserUpdateSerializer(CustomModelSerializer):
"""
用户修改-序列化器
"""
username = serializers.CharField(
max_length=50,
validators=[
CustomUniqueValidator(queryset=Users.objects.all(), message="账号必须唯一")
],
)
# password = serializers.CharField(required=False, allow_blank=True)
# mobile = serializers.CharField(
# max_length=50,
# validators=[
# CustomUniqueValidator(queryset=Users.objects.all(), message="手机号必须唯一")
# ],
# allow_blank=True
# )
def save(self, **kwargs):
data = super().save(**kwargs)
data.dept_belong_id = data.dept_id
data.save()
data.post.set(self.initial_data.get("post", []))
return data
class Meta:
model = Users
read_only_fields = ["id", "password"]
fields = "__all__"
extra_kwargs = {
"post": {"required": False, "read_only": True},
"mobile": {"required": False},
}
class UserInfoUpdateSerializer(CustomModelSerializer):
"""
用户修改-序列化器
"""
mobile = serializers.CharField(
max_length=50,
validators=[
CustomUniqueValidator(queryset=Users.objects.all(), message="手机号必须唯一")
],
allow_blank=True
)
def update(self, instance, validated_data):
return super().update(instance, validated_data)
class Meta:
model = Users
fields = ['email', 'mobile', 'avatar', 'name', 'gender']
extra_kwargs = {
"post": {"required": False, "read_only": True},
"mobile": {"required": False},
}
class ExportUserProfileSerializer(CustomModelSerializer):
"""
用户导出 序列化器
"""
last_login = serializers.DateTimeField(
format="%Y-%m-%d %H:%M:%S", required=False, read_only=True
)
is_active = serializers.SerializerMethodField(read_only=True)
dept_name = serializers.CharField(source="dept.name", default="")
dept_owner = serializers.CharField(source="dept.owner", default="")
gender = serializers.CharField(source="get_gender_display", read_only=True)
def get_is_active(self, instance):
return "启用" if instance.is_active else "停用"
class Meta:
model = Users
fields = (
"username",
"name",
"email",
"mobile",
"gender",
"is_active",
"last_login",
"dept_name",
"dept_owner",
)
class UserProfileImportSerializer(CustomModelSerializer):
password = serializers.CharField(read_only=True, required=False)
def save(self, **kwargs):
data = super().save(**kwargs)
password = hashlib.new(
"md5", str(self.initial_data.get("password", "admin123456")).encode(encoding="UTF-8")
).hexdigest()
data.set_password(password)
data.save()
return data
class Meta:
model = Users
exclude = (
"post",
"user_permissions",
"groups",
"is_superuser",
"date_joined",
)
class UserViewSet(CustomModelViewSet):
"""
用户接口
list:查询
create:新增
update:修改
retrieve:单例
destroy:删除
"""
queryset = Users.objects.exclude(is_superuser=1).all()
serializer_class = UserSerializer
create_serializer_class = UserCreateSerializer
update_serializer_class = UserUpdateSerializer
filter_fields = ["name", "username", "gender", "is_active", "dept", "user_type"]
search_fields = ["username", "name", "gender", "dept__name", "role__name"]
# 导出
export_field_label = {
"username": "用户账号",
"name": "用户名称",
"email": "用户邮箱",
"mobile": "手机号码",
"gender": "用户性别",
"is_active": "帐号状态",
"last_login": "最后登录时间",
"dept_name": "部门名称",
"dept_owner": "部门负责人",
}
export_serializer_class = ExportUserProfileSerializer
# 导入
import_serializer_class = UserProfileImportSerializer
import_field_dict = {
"username": "登录账号",
"name": "用户名称",
"email": "用户邮箱",
"mobile": "手机号码",
"gender": {
"title": "用户性别",
"choices": {
"data": {"未知": 2, "": 1, "": 0},
}
},
"is_active": {
"title": "帐号状态",
"choices": {
"data": {"启用": True, "禁用": False},
}
},
"dept": {"title": "部门", "choices": {"queryset": Dept.objects.filter(status=True), "values_name": "name"}},
"role": {"title": "角色", "choices": {"queryset": Role.objects.filter(status=True), "values_name": "name"}},
}
@action(methods=["GET"], detail=False, permission_classes=[IsAuthenticated])
def user_info(self, request):
"""获取当前用户信息"""
user = request.user
result = {
"id": user.id,
"username": user.username,
"name": user.name,
"mobile": user.mobile,
"user_type": user.user_type,
"gender": user.gender,
"email": user.email,
"avatar": user.avatar,
"dept": user.dept_id,
"is_superuser": user.is_superuser,
"role": user.role.values_list('id', flat=True),
}
if hasattr(connection, 'tenant'):
result['tenant_id'] = connection.tenant and connection.tenant.id
result['tenant_name'] = connection.tenant and connection.tenant.name
dept = getattr(user, 'dept', None)
if dept:
result['dept_info'] = {
'dept_id': dept.id,
'dept_name': dept.name
}
else:
result['dept_info'] = {
'dept_id': None,
'dept_name': "暂无部门"
}
role = getattr(user, 'role', None)
if role:
result['role_info'] = role.values('id', 'name', 'key')
return DetailResponse(data=result, msg="获取成功")
@action(methods=["PUT"], detail=False, permission_classes=[IsAuthenticated])
def update_user_info(self, request):
"""修改当前用户信息"""
serializer = UserInfoUpdateSerializer(request.user, data=request.data, request=request)
serializer.is_valid(raise_exception=True)
serializer.save()
return DetailResponse(data=None, msg="修改成功")
@action(methods=["PUT"], detail=True, permission_classes=[IsAuthenticated])
def change_password(self, request, *args, **kwargs):
"""密码修改"""
data = request.data
old_pwd = data.get("oldPassword")
new_pwd = data.get("newPassword")
new_pwd2 = data.get("newPassword2")
if old_pwd is None or new_pwd is None or new_pwd2 is None:
return ErrorResponse(msg="参数不能为空")
if new_pwd != new_pwd2:
return ErrorResponse(msg="两次密码不匹配")
verify_password = check_password(old_pwd, self.request.user.password)
if not verify_password:
verify_password = check_password(hashlib.md5(old_pwd.encode(encoding='UTF-8')).hexdigest(), self.request.user.password)
if verify_password:
request.user.password = make_password(new_pwd)
request.user.save()
return DetailResponse(data=None, msg="修改成功")
else:
return ErrorResponse(msg="旧密码不正确")
@action(methods=["PUT"], detail=True, permission_classes=[IsAuthenticated])
def reset_to_default_password(self, request, *args, **kwargs):
"""恢复默认密码"""
instance = Users.objects.filter(id=kwargs.get("pk")).first()
if instance:
instance.set_password(dispatch.get_system_config_values("base.default_password"))
instance.save()
return DetailResponse(data=None, msg="密码重置成功")
else:
return ErrorResponse(msg="未获取到用户")
@action(methods=["PUT"], detail=True)
def reset_password(self, request, pk):
"""
密码重置
"""
instance = Users.objects.filter(id=pk).first()
data = request.data
new_pwd = data.get("newPassword")
new_pwd2 = data.get("newPassword2")
if instance:
if new_pwd != new_pwd2:
return ErrorResponse(msg="两次密码不匹配")
else:
instance.password = make_password(new_pwd)
instance.save()
return DetailResponse(data=None, msg="修改成功")
else:
return ErrorResponse(msg="未获取到用户")