新功能: 添加后端代码

This commit is contained in:
李强
2023-01-21 10:56:53 +08:00
parent bb1f6dd128
commit f75c444699
122 changed files with 14109 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,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": null,
"is_value": true,
"status": true,
"sort": 1,
"remark": null,
"children": []
},
{
"label": "禁用",
"value": "false",
"parent": 1,
"type": 6,
"color": null,
"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": 66,
"type": 0,
"color": "success",
"is_value": true,
"status": true,
"sort": 1,
"remark": null,
"children": []
},
{
"label": "编辑",
"value": "Update",
"parent": 66,
"type": 0,
"color": "primary",
"is_value": true,
"status": true,
"sort": 2,
"remark": null,
"children": []
},
{
"label": "删除",
"value": "Delete",
"parent": 66,
"type": 0,
"color": "danger",
"is_value": true,
"status": true,
"sort": 3,
"remark": null,
"children": []
},
{
"label": "详情",
"value": "Retrieve",
"parent": 66,
"type": 0,
"color": "info",
"is_value": true,
"status": true,
"sort": 4,
"remark": null,
"children": []
},
{
"label": "查询",
"value": "Search",
"parent": 66,
"type": 0,
"color": "warning",
"is_value": true,
"status": true,
"sort": 5,
"remark": null,
"children": []
},
{
"label": "保存",
"value": "Save",
"parent": 66,
"type": 0,
"color": "success",
"is_value": true,
"status": true,
"sort": 6,
"remark": null,
"children": []
},
{
"label": "导入",
"value": "Import",
"parent": 66,
"type": 0,
"color": "primary",
"is_value": true,
"status": true,
"sort": 7,
"remark": null,
"children": []
},
{
"label": "导出",
"value": "Export",
"parent": 66,
"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": 7,
"type": 1,
"color": null,
"is_value": true,
"status": true,
"sort": 1,
"remark": null,
"children": []
},
{
"label": "禁用",
"value": "0",
"parent": 7,
"type": 1,
"color": null,
"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": 5,
"type": 6,
"color": null,
"is_value": true,
"status": true,
"sort": 1,
"remark": null,
"children": []
},
{
"label": "否",
"value": "false",
"parent": 5,
"type": 6,
"color": null,
"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": 10,
"type": 1,
"color": null,
"is_value": true,
"status": true,
"sort": 1,
"remark": null,
"children": []
},
{
"label": "否",
"value": "2",
"parent": 10,
"type": 1,
"color": null,
"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": 15,
"type": 1,
"color": null,
"is_value": true,
"status": true,
"sort": 1,
"remark": null,
"children": []
},
{
"label": "前台用户",
"value": "1",
"parent": 15,
"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": 49,
"type": 1,
"color": null,
"is_value": true,
"status": true,
"sort": 0,
"remark": null,
"children": []
},
{
"label": "textarea",
"value": "3",
"parent": 49,
"type": 1,
"color": "",
"is_value": true,
"status": true,
"sort": 0,
"remark": null,
"children": []
},
{
"label": "number",
"value": "10",
"parent": 49,
"type": 1,
"color": "",
"is_value": true,
"status": true,
"sort": 0,
"remark": null,
"children": []
},
{
"label": "datetime",
"value": "1",
"parent": 49,
"type": 1,
"color": null,
"is_value": true,
"status": true,
"sort": 1,
"remark": null,
"children": []
},
{
"label": "date",
"value": "2",
"parent": 49,
"type": 1,
"color": null,
"is_value": true,
"status": true,
"sort": 2,
"remark": null,
"children": []
},
{
"label": "time",
"value": "15",
"parent": 49,
"type": 1,
"color": "",
"is_value": true,
"status": true,
"sort": 3,
"remark": null,
"children": []
},
{
"label": "select",
"value": "4",
"parent": 49,
"type": 1,
"color": null,
"is_value": true,
"status": true,
"sort": 4,
"remark": null,
"children": []
},
{
"label": "checkbox",
"value": "5",
"parent": 49,
"type": 1,
"color": null,
"is_value": true,
"status": true,
"sort": 5,
"remark": null,
"children": []
},
{
"label": "radio",
"value": "6",
"parent": 49,
"type": 1,
"color": null,
"is_value": true,
"status": true,
"sort": 6,
"remark": null,
"children": []
},
{
"label": "switch",
"value": "9",
"parent": 49,
"type": 1,
"color": "",
"is_value": true,
"status": true,
"sort": 6,
"remark": null,
"children": []
},
{
"label": "文件附件",
"value": "8",
"parent": 49,
"type": 1,
"color": "",
"is_value": true,
"status": true,
"sort": 7,
"remark": null,
"children": []
},
{
"label": "图片(单张)",
"value": "7",
"parent": 49,
"type": 1,
"color": "",
"is_value": true,
"status": true,
"sort": 8,
"remark": null,
"children": []
},
{
"label": "图片(多张)",
"value": "12",
"parent": 49,
"type": 1,
"color": "",
"is_value": true,
"status": true,
"sort": 9,
"remark": null,
"children": []
},
{
"label": "数组",
"value": "11",
"parent": 49,
"type": 1,
"color": "",
"is_value": true,
"status": true,
"sort": 11,
"remark": null,
"children": []
},
{
"label": "关联表",
"value": "13",
"parent": 49,
"type": 1,
"color": "",
"is_value": true,
"status": true,
"sort": 13,
"remark": null,
"children": []
},
{
"label": "关联表(多选)",
"value": "14",
"parent": 49,
"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": 18,
"type": 1,
"color": null,
"is_value": true,
"status": true,
"sort": 0,
"remark": null,
"children": []
},
{
"label": "男",
"value": "1",
"parent": 18,
"type": 1,
"color": null,
"is_value": true,
"status": true,
"sort": 1,
"remark": null,
"children": []
},
{
"label": "女",
"value": "2",
"parent": 18,
"type": 1,
"color": null,
"is_value": true,
"status": true,
"sort": 2,
"remark": null,
"children": []
}
]
}
]

View File

@@ -0,0 +1,678 @@
[
{
"name": "系统管理",
"icon": "cog",
"sort": 1,
"is_link": false,
"is_catalog": true,
"web_path": "",
"component": "",
"component_name": "",
"status": true,
"cache": false,
"visible": true,
"parent": null,
"children": [
{
"name": "菜单管理",
"icon": "navicon",
"sort": 1,
"is_link": false,
"is_catalog": false,
"web_path": "/menu",
"component": "system/menu",
"component_name": "menu",
"status": true,
"cache": false,
"visible": true,
"parent": 277,
"children": [],
"menu_button": [
{
"name": "查询",
"value": "Search",
"api": "/api/system/menu/",
"method": 0
},
{
"name": "详情",
"value": "Retrieve",
"api": "/api/system/menu/{id}/",
"method": 0
},
{
"name": "新增",
"value": "Create",
"api": "/api/system/menu/",
"method": 1
},
{
"name": "编辑",
"value": "Update",
"api": "/api/system/menu/{id}/",
"method": 2
},
{
"name": "删除",
"value": "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": 277,
"children": [],
"menu_button": [
{
"name": "查询",
"value": "Search",
"api": "/api/system/menu_button/",
"method": 0
},
{
"name": "新增",
"value": "Create",
"api": "/api/system/menu_button/",
"method": 1
},
{
"name": "编辑",
"value": "Update",
"api": "/api/system/menu_button/{id}/",
"method": 2
},
{
"name": "删除",
"value": "Delete",
"api": "/api/system/menu_button/{id}/",
"method": 3
}
]
},
{
"name": "部门管理",
"icon": "bank",
"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": 277,
"children": [],
"menu_button": [
{
"name": "查询",
"value": "Search",
"api": "/api/system/dept/",
"method": 0
},
{
"name": "详情",
"value": "Retrieve",
"api": "/api/system/dept/{id}/",
"method": 0
},
{
"name": "新增",
"value": "Create",
"api": "/api/system/dept/",
"method": 1
},
{
"name": "编辑",
"value": "Update",
"api": "/api/system/dept/{id}/",
"method": 2
},
{
"name": "删除",
"value": "Delete",
"api": "/api/system/dept/{id}/",
"method": 3
}
]
},
{
"name": "角色管理",
"icon": "address-book",
"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": 277,
"children": [],
"menu_button": [
{
"name": "查询",
"value": "Search",
"api": "/api/system/role/",
"method": 0
},
{
"name": "详情",
"value": "Retrieve",
"api": "/api/system/role/{id}/",
"method": 0
},
{
"name": "新增",
"value": "Create",
"api": "/api/system/role/",
"method": 1
},
{
"name": "编辑",
"value": "Update",
"api": "/api/system/role/{id}/",
"method": 2
},
{
"name": "保存",
"value": "Save",
"api": "/api/system/role/{id}/",
"method": 2
},
{
"name": "删除",
"value": "Delete",
"api": "/api/system/role/{id}/",
"method": 3
}
]
},
{
"name": "用户管理",
"icon": "users",
"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": 277,
"children": [],
"menu_button": [
{
"name": "查询",
"value": "Search",
"api": "/api/system/user/",
"method": 0
},
{
"name": "详情",
"value": "Retrieve",
"api": "/api/system/user/{id}/",
"method": 0
},
{
"name": "新增",
"value": "Create",
"api": "/api/system/user/",
"method": 1
},
{
"name": "导出",
"value": "Export",
"api": "/api/system/user/export/",
"method": 1
},
{
"name": "导入",
"value": "Import",
"api": "/api/system/user/import/",
"method": 1
},
{
"name": "编辑",
"value": "Update",
"api": "/api/system/user/{id}/",
"method": 2
},
{
"name": "重设密码",
"value": "ResetPassword",
"api": "/api/system/user/{id}/reset_password/",
"method": 2
},
{
"name": "重置密码",
"value": "DefaultPassword",
"api": "/api/system/user/{id}/reset_to_default_password/",
"method": 2
},
{
"name": "删除",
"value": "Delete",
"api": "/api/system/user/{id}/",
"method": 3
}
]
},
{
"name": "消息中心",
"icon": "bullhorn",
"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": 277,
"children": [],
"menu_button": [
{
"name": "查询",
"value": "Search",
"api": "/api/system/message_center/",
"method": 0
},
{
"name": "详情",
"value": "Retrieve",
"api": "/api/system/message_center/{id}/",
"method": 0
},
{
"name": "新增",
"value": "Create",
"api": "/api/system/message_center/",
"method": 1
},
{
"name": "编辑",
"value": "Update",
"api": "/api/system/message_center/{id}/",
"method": 2
},
{
"name": "删除",
"value": "Delete",
"api": "/api/system/menu/{id}/",
"method": 3
}
]
},
{
"name": "接口白名单",
"icon": "compass",
"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": 277,
"children": [],
"menu_button": [
{
"name": "查询",
"value": "Search",
"api": "/api/system/api_white_list/",
"method": 0
},
{
"name": "详情",
"value": "Retrieve",
"api": "/api/system/api_white_list/{id}/",
"method": 0
},
{
"name": "新增",
"value": "Create",
"api": "/api/system/api_white_list/",
"method": 1
},
{
"name": "编辑",
"value": "Update",
"api": "/api/system/api_white_list/{id}/",
"method": 2
},
{
"name": "删除",
"value": "Delete",
"api": "/api/system/api_white_list/{id}/",
"method": 3
}
]
}
],
"menu_button": []
},
{
"name": "常规配置",
"icon": "cogs",
"sort": 2,
"is_link": false,
"is_catalog": true,
"web_path": "",
"component": "",
"component_name": "",
"status": true,
"cache": false,
"visible": true,
"parent": null,
"children": [
{
"name": "系统配置",
"icon": "desktop",
"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": 285,
"children": [],
"menu_button": [
{
"name": "查询",
"value": "Search",
"api": "/api/system/system_config/",
"method": 0
},
{
"name": "详情",
"value": "Retrieve",
"api": "/api/system/system_config/{id}/",
"method": 0
},
{
"name": "新增",
"value": "Create",
"api": "/api/system/system_config/",
"method": 1
},
{
"name": "编辑",
"value": "Update",
"api": "/api/system/system_config/{id}/",
"method": 2
},
{
"name": "删除",
"value": "Delete",
"api": "/api/system/system_config/{id}/",
"method": 3
}
]
},
{
"name": "字典管理",
"icon": "book",
"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": 285,
"children": [],
"menu_button": [
{
"name": "查询",
"value": "Search",
"api": "/api/system/dictionary/",
"method": 0
},
{
"name": "详情",
"value": "Retrieve",
"api": "/api/system/dictionary/{id}/",
"method": 0
},
{
"name": "新增",
"value": "Create",
"api": "/api/system/dictionary/",
"method": 1
},
{
"name": "编辑",
"value": "Update",
"api": "/api/system/dictionary/{id}/",
"method": 2
},
{
"name": "删除",
"value": "Delete",
"api": "/api/system/dictionary/{id}/",
"method": 3
}
]
},
{
"name": "地区管理",
"icon": "map",
"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": 285,
"children": [],
"menu_button": [
{
"name": "查询",
"value": "Search",
"api": "/api/system/area/",
"method": 0
},
{
"name": "详情",
"value": "Retrieve",
"api": "/api/system/area/{id}/",
"method": 0
},
{
"name": "新增",
"value": "Create",
"api": "/api/system/area/",
"method": 1
},
{
"name": "编辑",
"value": "Update",
"api": "/api/system/area/{id}/",
"method": 2
},
{
"name": "删除",
"value": "Delete",
"api": "/api/system/area/{id}/",
"method": 3
}
]
},
{
"name": "附件管理",
"icon": "file-text-o",
"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": 285,
"children": [],
"menu_button": [
{
"name": "详情",
"value": "Retrieve",
"api": "/api/system/file/{id}/",
"method": 0
},
{
"name": "查询",
"value": "Search",
"api": "/api/system/file/",
"method": 0
},
{
"name": "编辑",
"value": "Update",
"api": "/api/system/file/{id}/",
"method": 1
},
{
"name": "删除",
"value": "Delete",
"api": "/api/system/file/{id}/",
"method": 3
}
]
}
],
"menu_button": []
},
{
"name": "日志管理",
"icon": "book",
"sort": 3,
"is_link": false,
"is_catalog": true,
"web_path": "",
"component": "",
"component_name": "",
"status": true,
"cache": false,
"visible": true,
"parent": null,
"children": [
{
"name": "登录日志",
"icon": "file-text",
"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": 290,
"children": [],
"menu_button": [
{
"name": "查询",
"value": "Search",
"api": "/api/system/login_log/",
"method": 0
},
{
"name": "详情",
"value": "Retrieve",
"api": "/api/system/login_log/{id}/",
"method": 0
}
]
},
{
"name": "操作日志",
"icon": "file-code-o",
"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": 290,
"children": [],
"menu_button": [
{
"name": "详情",
"value": "Retrieve",
"api": "/api/system/operation_log/{id}/",
"method": 0
},
{
"name": "查询",
"value": "Search",
"api": "/api/system/operation_log/",
"method": 0
}
]
},
{
"name": "前端错误日志",
"icon": "bug",
"sort": 4,
"is_link": false,
"is_catalog": false,
"web_path": "/frontendLog",
"component": "system/log/frontendLog/index",
"component_name": "frontendLog",
"status": true,
"cache": false,
"visible": true,
"parent": 290,
"children": [],
"menu_button": []
}
],
"menu_button": []
},
{
"name": "DVAdmin官网",
"icon": "external-link",
"sort": 4,
"is_link": true,
"is_catalog": false,
"web_path": "https://django-vue-admin.com",
"component": "",
"component_name": "",
"status": true,
"cache": false,
"visible": true,
"parent": null,
"children": [],
"menu_button": []
}
]

View File

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

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,74 @@
# 初始化
import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "application.settings")
django.setup()
from dvadmin.system.views.user import UsersInitSerializer
from dvadmin.system.views.menu import MenuInitSerializer
from dvadmin.utils.core_initialize import CoreInitialize
from dvadmin.system.views.role import RoleInitSerializer
from dvadmin.system.views.api_white_list import ApiWhiteListInitSerializer
from dvadmin.system.views.dept import DeptInitSerializer
from dvadmin.system.views.dictionary import DictionaryInitSerializer
from dvadmin.system.views.system_config import SystemConfigInitSerializer
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_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_api_white_list()
self.init_dictionary()
self.init_system_config()
if __name__ == "__main__":
Initialize(app='dvadmin.system').run()

View File

@@ -0,0 +1,100 @@
import json
import logging
import os
import django
from django.db.models import QuerySet
from dvadmin.system.views.system_config import SystemConfigInitSerializer
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.views.api_white_list import ApiWhiteListInitSerializer
from dvadmin.system.views.dept import DeptInitSerializer
from dvadmin.system.views.dictionary import DictionaryInitSerializer
from dvadmin.system.views.menu import MenuInitSerializer
from dvadmin.system.views.role import RoleInitSerializer
from dvadmin.system.views.user import UsersInitSerializer
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,459 @@
import hashlib
import os
from django.contrib.auth.models import AbstractUser
from django.db import models
from application import dispatch
from dvadmin.utils.models import CoreModel, table_prefix
STATUS_CHOICES = (
(0, "禁用"),
(1, "启用"),
)
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="关联部门",
)
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 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")
DATASCOPE_CHOICES = (
(0, "仅本人数据权限"),
(1, "本部门及以下数据权限"),
(2, "本部门数据权限"),
(3, "全部数据权限"),
(4, "自定数据权限"),
)
data_range = models.IntegerField(default=0, choices=DATASCOPE_CHOICES, verbose_name="数据权限范围", help_text="数据权限范围")
remark = models.TextField(verbose_name="备注", help_text="备注", null=True, blank=True)
dept = models.ManyToManyField(to="Dept", verbose_name="数据权限-关联部门", db_constraint=False, help_text="数据权限-关联部门")
menu = models.ManyToManyField(to="Menu", verbose_name="关联菜单", db_constraint=False, help_text="关联菜单")
permission = models.ManyToManyField(
to="MenuButton", verbose_name="关联菜单的接口按钮", db_constraint=False, help_text="关联菜单的接口按钮"
)
class Meta:
db_table = table_prefix + "system_role"
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_dept_info(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_dept_info(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(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 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[0: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)
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()
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

View File

@@ -0,0 +1,43 @@
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.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)
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,51 @@
# -*- 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 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 ApiWhiteListViewSet(CustomModelViewSet):
"""
接口白名单
list:查询
create:新增
update:修改
retrieve:单例
destroy:删除
"""
queryset = ApiWhiteList.objects.all()
serializer_class = ApiWhiteListSerializer
# permission_classes = []

View File

@@ -0,0 +1,47 @@
# -*- 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)
def get_pcode_count(self, instance: Area):
return Area.objects.filter(pcode=instance).count()
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_backends = []

View File

@@ -0,0 +1,189 @@
# -*- coding: utf-8 -*-
"""
@author: H0nGzA1
@contact: QQ:2505811377
@Remark: 部门管理
"""
from rest_framework import serializers
from rest_framework.decorators import action
from dvadmin.system.models import Dept
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 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 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_backends = []
import_serializer_class = DeptImportSerializer
import_field_dict = {
"name": "部门名称",
"key": "部门标识",
}
def list(self, request, *args, **kwargs):
# 如果懒加载,则只返回父级
params = request.query_params
parent = params.get('parent', None)
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)
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:
data_range = request.user.role.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=[AnonymousUserPermission])
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,119 @@
# -*- 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 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 DictionaryCreateUpdateSerializer(CustomModelSerializer):
"""
字典管理 创建/更新时的列化器
"""
class Meta:
model = Dictionary
fields = '__all__'
class DictionaryViewSet(CustomModelViewSet):
"""
字典管理接口
list:查询
create:新增
update:修改
retrieve:单例
destroy:删除
"""
queryset = Dictionary.objects.all()
serializer_class = DictionarySerializer
extra_filter_backends = []
search_fields = ['label']
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,36 @@
from rest_framework import serializers
from dvadmin.system.models import FileList
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)
class Meta:
model = FileList
fields = "__all__"
def create(self, validated_data):
validated_data['name'] = str(self.initial_data.get('file'))
validated_data['url'] = self.initial_data.get('file')
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,185 @@
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("图片验证码错误")
data = super().validate(attrs)
data["name"] = self.user.name
data["userId"] = self.user.id
data["avatar"] = self.user.avatar
dept = getattr(self.user, 'dept', None)
if dept:
data['dept_info'] = {
'dept_id': dept.id,
'dept_name': dept.name,
'dept_key': dept.key
}
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 = []
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_backends = []

View File

@@ -0,0 +1,196 @@
# -*- 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
from dvadmin.system.views.menu_button import MenuButtonInitSerializer
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 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 WebRouterSerializer(CustomModelSerializer):
"""
前端菜单路由的简单序列化器
"""
path = serializers.CharField(source="web_path")
title = serializers.CharField(source="name")
menuPermission = serializers.SerializerMethodField(read_only=True)
def get_menuPermission(self, instance):
# 判断是否是超级管理员
if self.request.user.is_superuser:
return instance.menuPermission.values_list('value', flat=True)
else:
# 根据当前角色获取权限按钮id集合
permissionIds = self.request.user.role.values_list('permission', flat=True)
queryset = instance.menuPermission.filter(id__in=permissionIds, menu=instance.id).values_list('value', flat=True)
if queryset:
return queryset
else:
return None
class Meta:
model = Menu
fields = ('id', 'parent', 'icon', 'sort', 'path', 'name', 'title', 'is_link', 'is_catalog', 'web_path', 'component',
'component_name', 'cache', 'visible', 'menuPermission')
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_backends = []
@action(methods=['GET'], detail=False, permission_classes=[])
def web_router(self, request):
"""用于前端获取当前角色的路由"""
user = request.user
queryset = self.queryset.filter(status=1)
if not user.is_superuser:
menuIds = user.role.values_list('menu__id', flat=True)
queryset = Menu.objects.filter(id__in=menuIds, status=1)
serializer = WebRouterSerializer(queryset, many=True, request=request)
data = serializer.data
return SuccessResponse(data=data, total=len(data), msg="获取成功")
def list(self,request):
"""懒加载"""
params = request.query_params
parent = params.get('parent', None)
if params:
if parent:
queryset = self.queryset.filter(status=1, parent=parent)
else:
queryset = self.queryset.filter(status=1)
else:
queryset = self.queryset.filter(status=1, 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,59 @@
# -*- coding: utf-8 -*-
"""
@author: 猿小天
@contact: QQ:1638245306
@Created on: 2021/6/3 003 0:30
@Remark: 菜单按钮管理
"""
from dvadmin.system.models import MenuButton
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']
read_only_fields = ["id"]
class MenuButtonInitSerializer(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_backends = []

View File

@@ -0,0 +1,216 @@
# -*- 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()
return queryset.is_read
class Meta:
model = MessageCenter
fields = "__all__"
read_only_fields = ["id"]
def websocket_push(user_id, message):
"""
主动推送消息
"""
username = "user_"+str(user_id)
print(103,message)
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.exclude(is_deleted=True).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.exclude(is_deleted=True).filter(dept__id__in=target_dept).values_list('id', flat=True)
if target_type in [3]: # 系统通知
users = Users.objects.exclude(is_deleted=True).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)
print(queryset)
# 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, 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,217 @@
# -*- 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.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 RoleInitSerializer(CustomModelSerializer):
"""
初始化获取数信息(用于生成初始化json文件)
"""
class Meta:
model = Role
fields = ['name', 'key', 'sort', 'status', 'admin', 'data_range', 'remark',
'creator', 'dept_belong_id']
read_only_fields = ["id"]
extra_kwargs = {
'creator': {'write_only': True},
'dept_belong_id': {'write_only': True}
}
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)
data.dept.set(self.initial_data.get('dept', []))
data.menu.set(self.initial_data.get('menu', []))
data.permission.set(self.initial_data.get('permission', []))
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):
"""
角色管理接口
list:查询
create:新增
update:修改
retrieve:单例
destroy:删除
"""
queryset = Role.objects.all()
serializer_class = RoleSerializer
create_serializer_class = RoleCreateUpdateSerializer
update_serializer_class = RoleCreateUpdateSerializer
search_fields = ['name', 'key']
@action(methods=['GET'], detail=False, permission_classes=[IsAuthenticated])
def role_get_menu(self, request):
"""根据当前用户的角色返回角色拥有的菜单"""
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).all()
else:
menu_id_list = request.user.role.values_list('menu',flat=True)
queryset = Menu.objects.filter(id__in=menu_id_list)
# queryset = self.filter_queryset(queryset)
serializer = MenuPermissonSerializer(queryset, many=True,request=request)
return DetailResponse(data=serializer.data)
@action(methods=['GET'], detail=False, permission_classes=[IsAuthenticated])
def data_scope(self, request):
is_superuser = request.user.is_superuser
role_queryset = Role.objects.filter(users__id=request.user.id).values_list('data_range', flat=True)
if is_superuser:
data = [
{
"value": 0,
"label": '仅本人数据权限'
},
{
"value": 1,
"label": '本部门及以下数据权限'
},
{
"value": 2,
"label": '本部门数据权限'
},
{
"value": 3,
"label": '全部数据权限'
},
{
"value": 4,
"label": '自定义数据权限'
}
]
else:
data = []
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)
@action(methods=['GET'], detail=False, permission_classes=[IsAuthenticated])
def data_scope_dept(self,request):
"""根据当前角色获取部门信息"""
is_superuser = request.user.is_superuser
if is_superuser:
queryset = Dept.objects.values('id','name','parent')
else:
dept_list = request.user.role.values_list('dept',flat=True)
queryset = Dept.objects.filter(id__in=dept_list).values('id','name','parent')
return DetailResponse(data=queryset)

View File

@@ -0,0 +1,276 @@
# -*- 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 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}
}
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):
"""
系统配置子级-序列化器
"""
chinldern = serializers.SerializerMethodField()
form_item_type_label = serializers.CharField(source='get_form_item_type_display', read_only=True)
def get_chinldern(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,392 @@
import hashlib
from django.contrib.auth.hashers import make_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},
}
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 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 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):
"""
对密码进行验证
"""
password = self.initial_data.get("password")
if password:
return make_password(value)
return value
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},
}
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},
}
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},
}
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):
def save(self, **kwargs):
data = super().save(**kwargs)
password = hashlib.new(
"md5", str(self.initial_data.get("password", "")).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"]
filter_fields = {
"name": ["exact"],
"mobile": ["exact"],
"username": ["exact"],
"gender": ["icontains"],
"is_active": ["icontains"],
"dept": ["exact"],
"user_type": ["exact"],
}
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},
}
},
"password": "登录密码",
"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
}
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="两次密码不匹配")
check_password = request.user.check_password(old_pwd)
if not check_password:
check_password = request.user.check_password(hashlib.md5(old_pwd.encode(encoding='UTF-8')).hexdigest())
if check_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="未获取到用户")