From ef831bacb01ff0efa6574a5f83664a6fcf98d804 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E5=BC=BA?= <1206709430@qq.com>
Date: Mon, 25 Apr 2022 10:08:36 +0800
Subject: [PATCH 01/92] =?UTF-8?q?=E9=87=8D=E6=9E=84:=20=E6=B7=BB=E5=8A=A0?=
=?UTF-8?q?=E5=85=A8=E5=B1=80=E6=96=87=E4=BB=B6=E5=8F=8A=E5=9B=BE=E7=89=87?=
=?UTF-8?q?=E4=B8=8A=E4=BC=A0=E9=85=8D=E7=BD=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
backend/application/settings.py | 2 ++
web/src/install.js | 25 ++++++++++++----
.../components/header-user/userinfo.vue | 12 ++++----
.../store/modules/d2admin/modules/account.js | 2 +-
web/src/views/demo/page1/crud.js | 30 -------------------
web/src/views/system/user/crud.js | 14 ---------
6 files changed, 28 insertions(+), 57 deletions(-)
diff --git a/backend/application/settings.py b/backend/application/settings.py
index 8c60b21..bee5dfc 100644
--- a/backend/application/settings.py
+++ b/backend/application/settings.py
@@ -30,6 +30,8 @@ from conf.env import *
SECRET_KEY = 'django-insecure--z8%exyzt7e_%i@1+#1mm=%lb5=^fx_57=1@a+_y7bg5-w%)sm'
# 初始化plugins插件路径到环境变量中
PLUGINS_PATH = os.path.join(BASE_DIR, 'plugins')
+sys.path.insert(0, os.path.join(PLUGINS_PATH))
+
[sys.path.insert(0, os.path.join(PLUGINS_PATH, ele)) for ele in os.listdir(PLUGINS_PATH) if
os.path.isdir(os.path.join(PLUGINS_PATH, ele)) and not ele.startswith('__')]
diff --git a/web/src/install.js b/web/src/install.js
index b3e7c80..131ed75 100644
--- a/web/src/install.js
+++ b/web/src/install.js
@@ -15,7 +15,8 @@ import {
import { request } from '@/api/service'
import util from '@/libs/util'
import XEUtils from 'xe-utils'
-import { urlPrefix as deptPrefix } from '@/views/system/dept/api'
+import { urlPrefix as deptPrefix } from '@/views/system/dept/'
+const uploadUrl = util.baseURL() + 'api/system/file/'
/**
// vxe0
@@ -105,7 +106,7 @@ Vue.use(D2pFullEditor, {
Vue.use(D2pDemoExtend)
Vue.use(D2pFileUploader)
Vue.use(D2pUploader, {
- defaultType: 'cos',
+ defaultType: 'form',
cos: {
domain: 'https://d2p-demo-1251260344.cos.ap-guangzhou.myqcloud.com',
bucket: 'd2p-demo-1251260344',
@@ -159,8 +160,20 @@ Vue.use(D2pUploader, {
domain: 'http://d2p.file.veryreader.com'
},
form: {
- action: util.baseURL() + 'upload/form/upload',
- name: 'file'
+ action: uploadUrl,
+ name: 'file',
+ data: {}, // 上传附加参数
+ headers: {
+ Authorization: 'JWT ' + util.cookies.get('token')
+ },
+ type: 'form',
+ successHandle (ret, option) {
+ if (ret.data === null || ret.data === '') {
+ throw new Error('上传失败')
+ }
+ return { url: ret.data.data.url, key: option.data.key }
+ },
+ withCredentials: false // 是否带cookie
}
})
@@ -257,7 +270,7 @@ Vue.prototype.commonEndColumns = function (param = {}) {
type: 'table-selector',
dict: {
cache: true,
- url: '/api/system/dept/?limit=999&status=1',
+ url: deptPrefix + '?limit=999&status=1',
isTree: true,
value: 'id', // 数据字典中value字段的属性名
label: 'name', // 数据字典中label字段的属性名
@@ -267,7 +280,7 @@ Vue.prototype.commonEndColumns = function (param = {}) {
component
}) => {
return request({
- url: url,
+ url: url
}).then(ret => {
return ret.data.data
})
diff --git a/web/src/layout/header-aside/components/header-user/userinfo.vue b/web/src/layout/header-aside/components/header-user/userinfo.vue
index 67c8dff..d8d3fd2 100644
--- a/web/src/layout/header-aside/components/header-user/userinfo.vue
+++ b/web/src/layout/header-aside/components/header-user/userinfo.vue
@@ -149,7 +149,7 @@ export default {
headers: {
Authorization: 'JWT ' + util.cookies.get('token')
},
- fileList:[],
+ fileList: [],
userInfo: {
name: '',
gender: '',
@@ -197,7 +197,7 @@ export default {
params: {}
}).then((res) => {
_self.userInfo = res.data
- _self.fileList = [{name:'avatar.png',url:res.data.avatar}]
+ _self.fileList = [{ name: 'avatar.png', url: res.data.avatar }]
})
},
/**
@@ -278,10 +278,10 @@ export default {
* @param res
* @param file
*/
- handleAvatarSuccess(res, file) {
- console.log(11,res)
- this.fileList =[{ url: util.baseURL() + res.data.url, name:file.name }]
- this.userInfo.avatar = util.baseURL() + res.data.url;
+ handleAvatarSuccess (res, file) {
+ console.log(11, res)
+ this.fileList = [{ url: util.baseURL() + res.data.url, name: file.name }]
+ this.userInfo.avatar = util.baseURL() + res.data.url
}
}
}
diff --git a/web/src/store/modules/d2admin/modules/account.js b/web/src/store/modules/d2admin/modules/account.js
index ce612c4..2fdc0b1 100644
--- a/web/src/store/modules/d2admin/modules/account.js
+++ b/web/src/store/modules/d2admin/modules/account.js
@@ -42,7 +42,7 @@ export default {
util.cookies.set('token', res.access)
util.cookies.set('refresh', res.refresh)
// 设置 vuex 用户信息
- await dispatch('d2admin/user/set', { name: res.name, user_id: res.userId,avatar:res.avatar }, { root: true })
+ await dispatch('d2admin/user/set', { name: res.name, user_id: res.userId, avatar: res.avatar }, { root: true })
// 用户登录后从持久化数据加载一系列的设置
await dispatch('load')
},
diff --git a/web/src/views/demo/page1/crud.js b/web/src/views/demo/page1/crud.js
index 4829999..5919f81 100644
--- a/web/src/views/demo/page1/crud.js
+++ b/web/src/views/demo/page1/crud.js
@@ -1,6 +1,4 @@
import { request } from '@/api/service'
-import util from '@/libs/util'
-const uploadUrl = process.env.VUE_APP_API + '/api/system/img/'
export const crudOptions = (vm) => {
return {
pageOptions: {
@@ -85,20 +83,6 @@ export const crudOptions = (vm) => {
form: {
component: {
props: {
- uploader: {
- action: uploadUrl,
- name: 'file',
- headers: {
- Authorization: 'JWT ' + util.cookies.get('token')
- },
- type: 'form',
- successHandle (ret, option) {
- if (ret.data == null || ret.data === '') {
- throw new Error('上传失败')
- }
- return { url: ret.data.data.url, key: option.data.key }
- }
- },
elProps: { // 与el-uploader 配置一致
multiple: false,
limit: 5 // 限制5个文件
@@ -139,20 +123,6 @@ export const crudOptions = (vm) => {
form: {
component: {
props: {
- uploader: {
- action: uploadUrl,
- name: 'file',
- headers: {
- Authorization: 'JWT ' + util.cookies.get('token')
- },
- type: 'form',
- successHandle (ret, option) {
- if (ret.data == null || ret.data === '') {
- throw new Error('上传失败')
- }
- return { url: ret.data.data.url, key: option.data.key }
- }
- },
elProps: { // 与el-uploader 配置一致
multiple: false,
limit: 5 // 限制5个文件
diff --git a/web/src/views/system/user/crud.js b/web/src/views/system/user/crud.js
index ec101c7..ca46425 100644
--- a/web/src/views/system/user/crud.js
+++ b/web/src/views/system/user/crud.js
@@ -3,7 +3,6 @@ import { BUTTON_STATUS_BOOL } from '@/config/button'
import { urlPrefix as deptPrefix } from '../dept/api'
import util from '@/libs/util'
-const uploadUrl = util.baseURL() + 'api/system/file/'
export const crudOptions = (vm) => {
return {
pageOptions: {
@@ -264,19 +263,6 @@ export const crudOptions = (vm) => {
form: {
component: {
props: {
- uploader: {
- action: uploadUrl,
- headers: {
- Authorization: 'JWT ' + util.cookies.get('token')
- },
- type: 'form',
- successHandle (ret, option) {
- if (ret.data === null || ret.data === '') {
- throw new Error('上传失败')
- }
- return { url: util.baseURL() + ret.data.url, key: option.data.key }
- }
- },
elProps: { // 与el-uploader 配置一致
multiple: true,
limit: 5 // 限制5个文件
From c89148f6814442ba5318b993311dbc894f5874eb Mon Sep 17 00:00:00 2001
From: Angelo
Date: Mon, 25 Apr 2022 12:11:39 +0800
Subject: [PATCH 02/92] refactor(initialize data): bug fixed & refactor
initialize script
---
backend/dvadmin/system/initialize.py | 1420 -----------------
.../system/management/commands/init.py | 26 +-
backend/dvadmin/system/util/init_data.py | 1373 ++++++++++++++++
backend/dvadmin/system/util/initialize.py | 91 ++
backend/dvadmin/utils/serializers.py | 60 +-
.../d2-container/components/d2-source.vue | 19 +-
web/src/views/system/login/page.vue | 29 +-
7 files changed, 1540 insertions(+), 1478 deletions(-)
delete mode 100644 backend/dvadmin/system/initialize.py
create mode 100644 backend/dvadmin/system/util/init_data.py
create mode 100644 backend/dvadmin/system/util/initialize.py
diff --git a/backend/dvadmin/system/initialize.py b/backend/dvadmin/system/initialize.py
deleted file mode 100644
index a6d2198..0000000
--- a/backend/dvadmin/system/initialize.py
+++ /dev/null
@@ -1,1420 +0,0 @@
-# 初始化
-import datetime
-import os
-
-import django
-
-from dvadmin.utils.core_initialize import CoreInitialize
-
-os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
-django.setup()
-
-from dvadmin.system.models import Dept, Button, Menu, MenuButton, Role, Users
-
-
-class Initialize(CoreInitialize):
- creator_id = 1
-
- def init_dept(self):
- """
- 初始化部门信息
- """
- self.dept_data = [
- {
- "id": 1,
- "description": "",
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "DVAdmin团队",
- "sort": 1,
- "owner": "",
- "phone": "",
- "email": "",
- "status": 1,
- "creator_id": 1,
- "parent_id": None
- },
- {
- "id": 2,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 2,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "技术部",
- "sort": 1,
- "owner": None,
- "phone": None,
- "email": None,
- "status": 1,
- "creator_id": 1,
- "parent_id": 1
- },
- {
- "id": 3,
- "description": "",
- "modifier": "1",
- "dept_belong_id": 3,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "运营部",
- "sort": 2,
- "owner": "",
- "phone": "",
- "email": "",
- "status": 1,
- "creator_id": 1,
- "parent_id": 1
- }
- ]
- self.save(Dept, self.dept_data, "部门信息")
-
- def init_button(self):
- """
- 初始化按钮表
- """
- self.button_data = [
- {
- "id": 1,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "新增",
- "value": "Create",
- "creator_id": 1
- },
- {
- "id": 2,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "编辑",
- "value": "Update",
- "creator_id": 1
- },
- {
- "id": 3,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "删除",
- "value": "Delete",
- "creator_id": 1
- },
- {
- "id": 4,
- "description": "",
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "详情",
- "value": "Retrieve",
- "creator_id": 1
- },
- {
- "id": 5,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "查询",
- "value": "Search",
- "creator_id": 1
- },
- {
- "id": 6,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "保存",
- "value": "Save",
- "creator_id": 1
- },
- {
- "id": 7,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "导入",
- "value": "Import",
- "creator_id": 1
- },
- {
- "id": 8,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "导出",
- "value": "Export",
- "creator_id": 1
- },
- {
- "id": 9,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "重置密码",
- "value": "ResetPwd",
- "creator_id": 1
- }
- ]
- self.save(Button, self.button_data, "权限表标识")
-
- def init_menu(self):
- """
- 初始化菜单表
- """
- self.menu_data = [
- {
- "id": 1,
- "description": "",
- "modifier": "1",
- "dept_belong_id": "",
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "icon": "navicon",
- "name": "菜单管理",
- "sort": 1,
- "is_link": 0,
- "web_path": "/menu",
- "component": "system/menu",
- "component_name": "menu",
- "status": 1,
- "cache": 0,
- "visible": 1,
- "creator_id": 1,
- "parent_id": 2,
- "is_catalog": 0
- },
- {
- "id": 2,
- "description": "",
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "icon": "cog",
- "name": "系统管理",
- "sort": 1,
- "is_link": 0,
- "web_path": "",
- "component": "",
- "component_name": "",
- "status": 1,
- "cache": 0,
- "visible": 1,
- "creator_id": 1,
- "parent_id": None,
- "is_catalog": 1
- },
- {
- "id": 3,
- "description": "",
- "modifier": "1",
- "dept_belong_id": "",
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "icon": "users",
- "name": "用户管理",
- "sort": 6,
- "is_link": 0,
- "web_path": "/user",
- "component": "system/user/index",
- "component_name": "user",
- "status": 1,
- "cache": 0,
- "visible": 1,
- "creator_id": 1,
- "parent_id": 2,
- "is_catalog": 0
- },
- {
- "id": 4,
- "description": "",
- "modifier": "1",
- "dept_belong_id": "",
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "icon": "address-book",
- "name": "角色管理",
- "sort": 4,
- "is_link": 0,
- "web_path": "/role",
- "component": "system/role/index",
- "component_name": "role",
- "status": 1,
- "cache": 0,
- "visible": 1,
- "creator_id": 1,
- "parent_id": 2,
- "is_catalog": 0
- },
- {
- "id": 5,
- "description": "",
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "icon": "bank",
- "name": "部门管理",
- "sort": 3,
- "is_link": 0,
- "web_path": "/dept",
- "component": "system/dept/index",
- "component_name": "dept",
- "status": 1,
- "cache": 0,
- "visible": 1,
- "creator_id": 1,
- "parent_id": 2,
- "is_catalog": 0
- },
- {
- "id": 7,
- "description": "",
- "modifier": "1",
- "dept_belong_id": "",
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "icon": "dot-circle-o",
- "name": "菜单按钮",
- "sort": 2,
- "is_link": 0,
- "web_path": "/menuButton",
- "component": "system/menuButton/index",
- "component_name": "menuButton",
- "status": 1,
- "cache": 0,
- "visible": 0,
- "creator_id": 1,
- "parent_id": 2,
- "is_catalog": 0
- },
- {
- "id": 8,
- "description": "",
- "modifier": "1",
- "dept_belong_id": "",
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "icon": "bullseye",
- "name": "按钮管理",
- "sort": 2,
- "is_link": 0,
- "web_path": "/button",
- "component": "system/button/index",
- "component_name": "button",
- "status": 1,
- "cache": 0,
- "visible": 0,
- "creator_id": 1,
- "parent_id": 2,
- "is_catalog": 0
- },
- {
- "id": 9,
- "description": "",
- "modifier": "1",
- "dept_belong_id": "",
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "icon": "compass",
- "name": "接口白名单",
- "sort": 7,
- "is_link": 0,
- "web_path": "/apiWhiteList",
- "component": "system/whiteList/index",
- "component_name": "whiteList",
- "status": 1,
- "cache": 0,
- "visible": 1,
- "creator_id": 1,
- "parent_id": 2,
- "is_catalog": 0
- },
- {
- "id": 10,
- "description": "",
- "modifier": "1",
- "dept_belong_id": "",
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "icon": "book",
- "name": "字典管理",
- "sort": 1,
- "is_link": 0,
- "web_path": "/dictionary",
- "component": "system/dictionary/index",
- "component_name": "dictionary",
- "status": 1,
- "cache": 0,
- "visible": 1,
- "creator_id": 1,
- "parent_id": 17,
- "is_catalog": 0
- },
- {
- "id": 11,
- "description": "",
- "modifier": "1",
- "dept_belong_id": "",
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "icon": "map",
- "name": "地区管理",
- "sort": 2,
- "is_link": 0,
- "web_path": "/areas",
- "component": "system/areas/index",
- "component_name": "areas",
- "status": 1,
- "cache": 0,
- "visible": 1,
- "creator_id": 1,
- "parent_id": 17,
- "is_catalog": 0
- },
- {
- "id": 13,
- "description": "",
- "modifier": "1",
- "dept_belong_id": "",
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "icon": "file-text-o",
- "name": "附件管理",
- "sort": 3,
- "is_link": 0,
- "web_path": "/file",
- "component": "system/fileList/index",
- "component_name": "file",
- "status": 1,
- "cache": 0,
- "visible": 1,
- "creator_id": 1,
- "parent_id": 17,
- "is_catalog": 0
- },
- {
- "id": 15,
- "description": "",
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "icon": "book",
- "name": "日志管理",
- "sort": 3,
- "is_link": 0,
- "web_path": "",
- "component": "",
- "component_name": "",
- "status": 1,
- "cache": 0,
- "visible": 1,
- "creator_id": 1,
- "parent_id": None,
- "is_catalog": 1
- },
- {
- "id": 16,
- "description": "",
- "modifier": "1",
- "dept_belong_id": "",
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "icon": "file-code-o",
- "name": "操作日志",
- "sort": 2,
- "is_link": 0,
- "web_path": "/operationLog",
- "component": "system/log/operationLog/index",
- "component_name": "operationLog",
- "status": 1,
- "cache": 0,
- "visible": 1,
- "creator_id": 1,
- "parent_id": 15,
- "is_catalog": 0
- },
- {
- "id": 17,
- "description": "",
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "icon": "cogs",
- "name": "常规配置",
- "sort": 2,
- "is_link": 0,
- "web_path": "",
- "component": "",
- "component_name": "",
- "status": 1,
- "cache": 0,
- "visible": 1,
- "creator_id": 1,
- "parent_id": None,
- "is_catalog": 1
- },
- {
- "id": 18,
- "description": "",
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "icon": "external-link",
- "name": "DVAdmin官网",
- "sort": 4,
- "is_link": 1,
- "web_path": "https://django-vue-admin.com",
- "component": "",
- "component_name": "",
- "status": 1,
- "cache": 0,
- "visible": 1,
- "creator_id": 1,
- "parent_id": None,
- "is_catalog": 0
- },
- {
- "id": 19,
- "description": "",
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "icon": "bug",
- "name": "前端错误日志",
- "sort": 4,
- "is_link": 0,
- "web_path": "/frontendLog",
- "component": "system/log/frontendLog/index",
- "component_name": "frontendLog",
- "status": 1,
- "cache": 0,
- "visible": 1,
- "creator_id": 1,
- "parent_id": 15,
- "is_catalog": 0
- },
- {
- "id": 20,
- "description": "",
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "icon": "file-text",
- "name": "登录日志",
- "sort": 1,
- "is_link": 0,
- "web_path": "/loginLog",
- "component": "system/log/loginLog/index",
- "component_name": "loginLog",
- "status": 1,
- "cache": 0,
- "visible": 1,
- "creator_id": 1,
- "parent_id": 15,
- "is_catalog": 0
- }
- ]
- self.save(Menu, self.menu_data, "菜单表")
-
- def init_menu_button(self):
- """
- 初始化菜单按钮表
- """
- self.menu_button_data = [
- {
- "id": 1,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "查询",
- "value": "Search",
- "api": "/api/system/menu/",
- "method": 0,
- "creator_id": 1,
- "menu_id": 1
- },
- {
- "id": 2,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "编辑",
- "value": "Update",
- "api": "/api/system/menu/{id}/",
- "method": 2,
- "creator_id": 1,
- "menu_id": 1
- },
- {
- "id": 3,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "新增",
- "value": "Create",
- "api": "/api/system/menu/",
- "method": 1,
- "creator_id": 1,
- "menu_id": 1
- },
- {
- "id": 4,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "详情",
- "value": "Retrieve",
- "api": "/api/system/menu/{id}/",
- "method": 0,
- "creator_id": 1,
- "menu_id": 1
- },
- {
- "id": 5,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "删除",
- "value": "Delete",
- "api": "/api/system/menu/{id}/",
- "method": 3,
- "creator_id": 1,
- "menu_id": 1
- },
- {
- "id": 6,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "编辑",
- "value": "Update",
- "api": "/api/system/user/{id}/",
- "method": 2,
- "creator_id": 1,
- "menu_id": 3
- },
- {
- "id": 7,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "查询",
- "value": "Search",
- "api": "/api/system/user/",
- "method": 0,
- "creator_id": 1,
- "menu_id": 3
- },
- {
- "id": 8,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "详情",
- "value": "Retrieve",
- "api": "/api/system/user/{id}/",
- "method": 0,
- "creator_id": 1,
- "menu_id": 3
- },
- {
- "id": 9,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "新增",
- "value": "Create",
- "api": "/api/system/user/",
- "method": 1,
- "creator_id": 1,
- "menu_id": 3
- },
- {
- "id": 10,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "删除",
- "value": "Delete",
- "api": "/api/system/user/{id}/",
- "method": 3,
- "creator_id": 1,
- "menu_id": 3
- },
- {
- "id": 11,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "编辑",
- "value": "Update",
- "api": "/api/system/role/{id}/",
- "method": 2,
- "creator_id": 1,
- "menu_id": 4
- },
- {
- "id": 12,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "查询",
- "value": "Search",
- "api": "/api/system/role/",
- "method": 0,
- "creator_id": 1,
- "menu_id": 4
- },
- {
- "id": 13,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "详情",
- "value": "Retrieve",
- "api": "/api/system/role/{id}/",
- "method": 0,
- "creator_id": 1,
- "menu_id": 4
- },
- {
- "id": 14,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "新增",
- "value": "Create",
- "api": "/api/system/role/",
- "method": 1,
- "creator_id": 1,
- "menu_id": 4
- },
- {
- "id": 15,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "删除",
- "value": "Delete",
- "api": "/api/system/role/{id}/",
- "method": 3,
- "creator_id": 1,
- "menu_id": 4
- },
- {
- "id": 16,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "编辑",
- "value": "Update",
- "api": "/api/system/dept/{id}/",
- "method": 2,
- "creator_id": 1,
- "menu_id": 5
- },
- {
- "id": 17,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "查询",
- "value": "Search",
- "api": "/api/system/dept/",
- "method": 0,
- "creator_id": 1,
- "menu_id": 5
- },
- {
- "id": 18,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "详情",
- "value": "Retrieve",
- "api": "/api/system/dept/{id}/",
- "method": 0,
- "creator_id": 1,
- "menu_id": 5
- },
- {
- "id": 19,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "新增",
- "value": "Create",
- "api": "/api/system/dept/",
- "method": 1,
- "creator_id": 1,
- "menu_id": 5
- },
- {
- "id": 20,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "删除",
- "value": "Delete",
- "api": "/api/system/dept/{id}/",
- "method": 3,
- "creator_id": 1,
- "menu_id": 5
- },
- {
- "id": 21,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "编辑",
- "value": "Update",
- "api": "/api/system/menu_button/{id}/",
- "method": 2,
- "creator_id": 1,
- "menu_id": 7
- },
- {
- "id": 22,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "查询",
- "value": "Search",
- "api": "/api/system/menu_button/",
- "method": 0,
- "creator_id": 1,
- "menu_id": 7
- },
- {
- "id": 23,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "新增",
- "value": "Create",
- "api": "/api/system/menu_button/",
- "method": 1,
- "creator_id": 1,
- "menu_id": 7
- },
- {
- "id": 24,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "删除",
- "value": "Delete",
- "api": "/api/system/menu_button/{id}/",
- "method": 3,
- "creator_id": 1,
- "menu_id": 7
- },
- {
- "id": 25,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "新增",
- "value": "Create",
- "api": "/api/system/button/",
- "method": 1,
- "creator_id": 1,
- "menu_id": 8
- },
- {
- "id": 26,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "编辑",
- "value": "Update",
- "api": "/api/system/button/{id}/",
- "method": 2,
- "creator_id": 1,
- "menu_id": 8
- },
- {
- "id": 27,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "查询",
- "value": "Search",
- "api": "/api/system/button/",
- "method": 0,
- "creator_id": 1,
- "menu_id": 8
- },
- {
- "id": 28,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "删除",
- "value": "Delete",
- "api": "/api/system/button/{id}/",
- "method": 3,
- "creator_id": 1,
- "menu_id": 8
- },
- {
- "id": 29,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "保存",
- "value": "Save",
- "api": "/api/system/role/{id}/",
- "method": 2,
- "creator_id": 1,
- "menu_id": 6
- },
- {
- "id": 30,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "编辑",
- "value": "Update",
- "api": "/api/system/api_white_list/{id}/",
- "method": 2,
- "creator_id": 1,
- "menu_id": 9
- },
- {
- "id": 31,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "查询",
- "value": "Search",
- "api": "/api/system/api_white_list/",
- "method": 0,
- "creator_id": 1,
- "menu_id": 9
- },
- {
- "id": 32,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "详情",
- "value": "Retrieve",
- "api": "/api/system/api_white_list/{id}/",
- "method": 0,
- "creator_id": 1,
- "menu_id": 9
- },
- {
- "id": 33,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "新增",
- "value": "Create",
- "api": "/api/system/api_white_list/",
- "method": 1,
- "creator_id": 1,
- "menu_id": 9
- },
- {
- "id": 34,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "删除",
- "value": "Delete",
- "api": "/api/system/api_white_list/{id}/",
- "method": 3,
- "creator_id": 1,
- "menu_id": 9
- },
- {
- "id": 35,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "编辑",
- "value": "Update",
- "api": "/api/system/dictionary/{id}/",
- "method": 2,
- "creator_id": 1,
- "menu_id": 10
- },
- {
- "id": 36,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "查询",
- "value": "Search",
- "api": "/api/system/dictionary/",
- "method": 0,
- "creator_id": 1,
- "menu_id": 10
- },
- {
- "id": 37,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "详情",
- "value": "Retrieve",
- "api": "/api/system/dictionary/{id}/",
- "method": 0,
- "creator_id": 1,
- "menu_id": 10
- },
- {
- "id": 38,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "新增",
- "value": "Create",
- "api": "/api/system/dictionary/",
- "method": 1,
- "creator_id": 1,
- "menu_id": 10
- },
- {
- "id": 39,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "删除",
- "value": "Delete",
- "api": "/api/system/dictionary/{id}/",
- "method": 3,
- "creator_id": 1,
- "menu_id": 10
- },
- {
- "id": 40,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "编辑",
- "value": "Update",
- "api": "/api/system/area/{id}/",
- "method": 2,
- "creator_id": 1,
- "menu_id": 11
- },
- {
- "id": 41,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "查询",
- "value": "Search",
- "api": "/api/system/area/",
- "method": 0,
- "creator_id": 1,
- "menu_id": 11
- },
- {
- "id": 42,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "详情",
- "value": "Retrieve",
- "api": "/api/system/area/{id}/",
- "method": 0,
- "creator_id": 1,
- "menu_id": 11
- },
- {
- "id": 43,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "新增",
- "value": "Create",
- "api": "/api/system/area/",
- "method": 1,
- "creator_id": 1,
- "menu_id": 11
- },
- {
- "id": 44,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "删除",
- "value": "Delete",
- "api": "/api/system/area/{id}/",
- "method": 3,
- "creator_id": 1,
- "menu_id": 11
- },
- {
- "id": 45,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "详情",
- "value": "Retrieve",
- "api": "/api/system/operation_log/{id}/",
- "method": 0,
- "creator_id": 1,
- "menu_id": 16
- },
- {
- "id": 46,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "查询",
- "value": "Search",
- "api": "/api/system/operation_log/",
- "method": 0,
- "creator_id": 1,
- "menu_id": 16
- },
- {
- "id": 47,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "导出",
- "value": "Export",
- "api": "/api/system/user/export/",
- "method": 1,
- "creator_id": 1,
- "menu_id": 3
- },
- {
- "id": 48,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "导入",
- "value": "Import",
- "api": "/api/system/user/import/",
- "method": 1,
- "creator_id": 1,
- "menu_id": 3
- },
- {
- "id": 49,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "详情",
- "value": "Retrieve",
- "api": "/api/system/file/{id}/",
- "method": 0,
- "creator_id": 1,
- "menu_id": 13
- },
- {
- "id": 50,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "查询",
- "value": "Search",
- "api": "/api/system/file/",
- "method": 0,
- "creator_id": 1,
- "menu_id": 13
- },
- {
- "id": 51,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "删除",
- "value": "Delete",
- "api": "/api/system/file/{id}/",
- "method": 3,
- "creator_id": 1,
- "menu_id": 13
- },
- {
- "id": 52,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "编辑",
- "value": "Update",
- "api": "/api/system/file/{id}/",
- "method": 1,
- "creator_id": 1,
- "menu_id": 13
- },
- {
- "id": 53,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "重置密码",
- "value": "ResetPwd",
- "api": "/api/system/user/reset_password/{id}/",
- "method": 2,
- "creator_id": 1,
- "menu_id": 3
- },{
- "id": 54,
- "description": None,
- "modifier": "1",
- "dept_belong_id": "1",
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "查询",
- "value": "Search",
- "api": "/api/system/login_log/",
- "method": 0,
- "creator_id": 1,
- "menu_id": 20
- },
- {
- "id": 55,
- "description": None,
- "modifier": "1",
- "dept_belong_id": "1",
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "详情",
- "value": "Retrieve",
- "api": "/api/system/login_log/{id}/",
- "method": 0,
- "creator_id": 1,
- "menu_id": 20
- }
- ]
- self.save(MenuButton, self.menu_button_data, "菜单按钮表")
-
- def init_role(self):
- """
- 初始化角色表
- """
- data = [
- {
- "id": 1,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "name": "管理员",
- "key": "admin",
- "sort": 1,
- "status": 1,
- "admin": 1,
- "data_range": 3,
- "menu": [ele.get("id") for ele in self.menu_data],
- "permission": [ele.get("id") for ele in self.menu_button_data],
- "remark": None,
- "creator_id": 1
- }
- ]
- self.save(Role, data, "角色表")
-
- def init_users(self):
- """
- 初始化用户表
- """
- data = [
- {
- "password": "pbkdf2_sha256$260000$g17x5wlSiW1FZAh1Eudchw$ZeSAqj3Xak0io8v/pmPW0BX9EX5R2zFXDwbbD68oBFk=",
- "last_login": None,
- "is_superuser": 1,
- "first_name": "",
- "last_name": "",
- "is_staff": 1,
- "is_active": 1,
- "id": 1,
- "description": None,
- "modifier": "1",
- "dept_belong_id": 1,
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "username": "superadmin",
- "email": "dvadmin@django-vue-admin.com",
- "mobile": "13333333333",
- "avatar": None,
- "name": "超级管理员",
- "gender": 1,
- "creator_id": None,
- "dept_id": 1
- },
- {
- "password": "pbkdf2_sha256$260000$g17x5wlSiW1FZAh1Eudchw$ZeSAqj3Xak0io8v/pmPW0BX9EX5R2zFXDwbbD68oBFk=",
- "last_login": None,
- "is_superuser": 0,
- "first_name": "",
- "last_name": "",
- "is_staff": 1,
- "is_active": 1,
- "id": 2,
- "description": "",
- "modifier": "1",
- "dept_belong_id": "",
- "update_datetime": datetime.datetime.now(),
- "create_datetime": datetime.datetime.now(),
- "username": "admin",
- "email": "dvadmin@django-vue-admin.com",
- "mobile": "13333333333",
- "avatar": "",
- "name": "管理员",
- "gender": 1,
- "creator_id": None,
- "dept_id": 1,
- "role": [1],
- }
- ]
- self.save(Users, data, "用户表", no_reset=True)
-
- def run(self):
- self.init_dept()
- self.init_button()
- self.init_menu()
- self.init_menu_button()
- self.init_role()
- self.init_users()
-
-
-# 项目init 初始化,默认会执行 main 方法进行初始化
-def main(reset=False):
- Initialize(reset).run()
- pass
-
-
-if __name__ == '__main__':
- main()
diff --git a/backend/dvadmin/system/management/commands/init.py b/backend/dvadmin/system/management/commands/init.py
index 4a168f4..4a299b5 100644
--- a/backend/dvadmin/system/management/commands/init.py
+++ b/backend/dvadmin/system/management/commands/init.py
@@ -13,27 +13,33 @@ class Command(BaseCommand):
"""
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='*')
+ 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):
+ 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):
+ if isinstance(options.get("n"), list) or isinstance(options.get("N"), list):
reset = False
print(f"正在准备初始化数据,{'如有初始化数据,将会不做操作跳过' if not reset else '初始数据将会先删除后新增'}...")
for app in settings.INSTALLED_APPS:
try:
- exec(f"""
-from {app}.initialize import main
+ exec(
+ f"""
+from {app}.util.initialize import main
main(reset={reset})
- """)
+ """
+ )
except ModuleNotFoundError:
pass
print("初始化数据完成!")
diff --git a/backend/dvadmin/system/util/init_data.py b/backend/dvadmin/system/util/init_data.py
new file mode 100644
index 0000000..e7f5e5a
--- /dev/null
+++ b/backend/dvadmin/system/util/init_data.py
@@ -0,0 +1,1373 @@
+import datetime
+
+
+dept_data = [
+ {
+ "id": 1,
+ "description": "",
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "DVAdmin团队",
+ "sort": 1,
+ "owner": "",
+ "phone": "",
+ "email": "",
+ "status": 1,
+ "creator_id": 1,
+ "parent_id": None,
+ },
+ {
+ "id": 2,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 2,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "技术部",
+ "sort": 1,
+ "owner": None,
+ "phone": None,
+ "email": None,
+ "status": 1,
+ "creator_id": 1,
+ "parent_id": 1,
+ },
+ {
+ "id": 3,
+ "description": "",
+ "modifier": "1",
+ "dept_belong_id": 3,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "运营部",
+ "sort": 2,
+ "owner": "",
+ "phone": "",
+ "email": "",
+ "status": 1,
+ "creator_id": 1,
+ "parent_id": 1,
+ },
+]
+
+button_data = [
+ {
+ "id": 1,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "新增",
+ "value": "Create",
+ "creator_id": 1,
+ },
+ {
+ "id": 2,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "编辑",
+ "value": "Update",
+ "creator_id": 1,
+ },
+ {
+ "id": 3,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "删除",
+ "value": "Delete",
+ "creator_id": 1,
+ },
+ {
+ "id": 4,
+ "description": "",
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "详情",
+ "value": "Retrieve",
+ "creator_id": 1,
+ },
+ {
+ "id": 5,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "查询",
+ "value": "Search",
+ "creator_id": 1,
+ },
+ {
+ "id": 6,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "保存",
+ "value": "Save",
+ "creator_id": 1,
+ },
+ {
+ "id": 7,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "导入",
+ "value": "Import",
+ "creator_id": 1,
+ },
+ {
+ "id": 8,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "导出",
+ "value": "Export",
+ "creator_id": 1,
+ },
+ {
+ "id": 9,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "重置密码",
+ "value": "ResetPwd",
+ "creator_id": 1,
+ },
+]
+
+menu_data = [
+ {
+ "id": 1,
+ "description": "",
+ "modifier": "1",
+ "dept_belong_id": "",
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "icon": "navicon",
+ "name": "菜单管理",
+ "sort": 1,
+ "is_link": 0,
+ "web_path": "/menu",
+ "component": "system/menu",
+ "component_name": "menu",
+ "status": 1,
+ "cache": 0,
+ "visible": 1,
+ "creator_id": 1,
+ "parent_id": 2,
+ "is_catalog": 0,
+ },
+ {
+ "id": 2,
+ "description": "",
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "icon": "cog",
+ "name": "系统管理",
+ "sort": 1,
+ "is_link": 0,
+ "web_path": "",
+ "component": "",
+ "component_name": "",
+ "status": 1,
+ "cache": 0,
+ "visible": 1,
+ "creator_id": 1,
+ "parent_id": None,
+ "is_catalog": 1,
+ },
+ {
+ "id": 3,
+ "description": "",
+ "modifier": "1",
+ "dept_belong_id": "",
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "icon": "users",
+ "name": "用户管理",
+ "sort": 6,
+ "is_link": 0,
+ "web_path": "/user",
+ "component": "system/user/index",
+ "component_name": "user",
+ "status": 1,
+ "cache": 0,
+ "visible": 1,
+ "creator_id": 1,
+ "parent_id": 2,
+ "is_catalog": 0,
+ },
+ {
+ "id": 4,
+ "description": "",
+ "modifier": "1",
+ "dept_belong_id": "",
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "icon": "address-book",
+ "name": "角色管理",
+ "sort": 4,
+ "is_link": 0,
+ "web_path": "/role",
+ "component": "system/role/index",
+ "component_name": "role",
+ "status": 1,
+ "cache": 0,
+ "visible": 1,
+ "creator_id": 1,
+ "parent_id": 2,
+ "is_catalog": 0,
+ },
+ {
+ "id": 5,
+ "description": "",
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "icon": "bank",
+ "name": "部门管理",
+ "sort": 3,
+ "is_link": 0,
+ "web_path": "/dept",
+ "component": "system/dept/index",
+ "component_name": "dept",
+ "status": 1,
+ "cache": 0,
+ "visible": 1,
+ "creator_id": 1,
+ "parent_id": 2,
+ "is_catalog": 0,
+ },
+ {
+ "id": 7,
+ "description": "",
+ "modifier": "1",
+ "dept_belong_id": "",
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "icon": "dot-circle-o",
+ "name": "菜单按钮",
+ "sort": 2,
+ "is_link": 0,
+ "web_path": "/menuButton",
+ "component": "system/menuButton/index",
+ "component_name": "menuButton",
+ "status": 1,
+ "cache": 0,
+ "visible": 0,
+ "creator_id": 1,
+ "parent_id": 2,
+ "is_catalog": 0,
+ },
+ {
+ "id": 8,
+ "description": "",
+ "modifier": "1",
+ "dept_belong_id": "",
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "icon": "bullseye",
+ "name": "按钮管理",
+ "sort": 2,
+ "is_link": 0,
+ "web_path": "/button",
+ "component": "system/button/index",
+ "component_name": "button",
+ "status": 1,
+ "cache": 0,
+ "visible": 0,
+ "creator_id": 1,
+ "parent_id": 2,
+ "is_catalog": 0,
+ },
+ {
+ "id": 9,
+ "description": "",
+ "modifier": "1",
+ "dept_belong_id": "",
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "icon": "compass",
+ "name": "接口白名单",
+ "sort": 7,
+ "is_link": 0,
+ "web_path": "/apiWhiteList",
+ "component": "system/whiteList/index",
+ "component_name": "whiteList",
+ "status": 1,
+ "cache": 0,
+ "visible": 1,
+ "creator_id": 1,
+ "parent_id": 2,
+ "is_catalog": 0,
+ },
+ {
+ "id": 10,
+ "description": "",
+ "modifier": "1",
+ "dept_belong_id": "",
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "icon": "book",
+ "name": "字典管理",
+ "sort": 1,
+ "is_link": 0,
+ "web_path": "/dictionary",
+ "component": "system/dictionary/index",
+ "component_name": "dictionary",
+ "status": 1,
+ "cache": 0,
+ "visible": 1,
+ "creator_id": 1,
+ "parent_id": 17,
+ "is_catalog": 0,
+ },
+ {
+ "id": 11,
+ "description": "",
+ "modifier": "1",
+ "dept_belong_id": "",
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "icon": "map",
+ "name": "地区管理",
+ "sort": 2,
+ "is_link": 0,
+ "web_path": "/areas",
+ "component": "system/areas/index",
+ "component_name": "areas",
+ "status": 1,
+ "cache": 0,
+ "visible": 1,
+ "creator_id": 1,
+ "parent_id": 17,
+ "is_catalog": 0,
+ },
+ {
+ "id": 13,
+ "description": "",
+ "modifier": "1",
+ "dept_belong_id": "",
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "icon": "file-text-o",
+ "name": "附件管理",
+ "sort": 3,
+ "is_link": 0,
+ "web_path": "/file",
+ "component": "system/fileList/index",
+ "component_name": "file",
+ "status": 1,
+ "cache": 0,
+ "visible": 1,
+ "creator_id": 1,
+ "parent_id": 17,
+ "is_catalog": 0,
+ },
+ {
+ "id": 15,
+ "description": "",
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "icon": "book",
+ "name": "日志管理",
+ "sort": 3,
+ "is_link": 0,
+ "web_path": "",
+ "component": "",
+ "component_name": "",
+ "status": 1,
+ "cache": 0,
+ "visible": 1,
+ "creator_id": 1,
+ "parent_id": None,
+ "is_catalog": 1,
+ },
+ {
+ "id": 16,
+ "description": "",
+ "modifier": "1",
+ "dept_belong_id": "",
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "icon": "file-code-o",
+ "name": "操作日志",
+ "sort": 2,
+ "is_link": 0,
+ "web_path": "/operationLog",
+ "component": "system/log/operationLog/index",
+ "component_name": "operationLog",
+ "status": 1,
+ "cache": 0,
+ "visible": 1,
+ "creator_id": 1,
+ "parent_id": 15,
+ "is_catalog": 0,
+ },
+ {
+ "id": 17,
+ "description": "",
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "icon": "cogs",
+ "name": "常规配置",
+ "sort": 2,
+ "is_link": 0,
+ "web_path": "",
+ "component": "",
+ "component_name": "",
+ "status": 1,
+ "cache": 0,
+ "visible": 1,
+ "creator_id": 1,
+ "parent_id": None,
+ "is_catalog": 1,
+ },
+ {
+ "id": 18,
+ "description": "",
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "icon": "external-link",
+ "name": "DVAdmin官网",
+ "sort": 4,
+ "is_link": 1,
+ "web_path": "https://django-vue-admin.com",
+ "component": "",
+ "component_name": "",
+ "status": 1,
+ "cache": 0,
+ "visible": 1,
+ "creator_id": 1,
+ "parent_id": None,
+ "is_catalog": 0,
+ },
+ {
+ "id": 19,
+ "description": "",
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "icon": "bug",
+ "name": "前端错误日志",
+ "sort": 4,
+ "is_link": 0,
+ "web_path": "/frontendLog",
+ "component": "system/log/frontendLog/index",
+ "component_name": "frontendLog",
+ "status": 1,
+ "cache": 0,
+ "visible": 1,
+ "creator_id": 1,
+ "parent_id": 15,
+ "is_catalog": 0,
+ },
+ {
+ "id": 20,
+ "description": "",
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "icon": "file-text",
+ "name": "登录日志",
+ "sort": 1,
+ "is_link": 0,
+ "web_path": "/loginLog",
+ "component": "system/log/loginLog/index",
+ "component_name": "loginLog",
+ "status": 1,
+ "cache": 0,
+ "visible": 1,
+ "creator_id": 1,
+ "parent_id": 15,
+ "is_catalog": 0,
+ },
+]
+
+menu_button_data = [
+ {
+ "id": 1,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "查询",
+ "value": "Search",
+ "api": "/api/system/menu/",
+ "method": 0,
+ "creator_id": 1,
+ "menu_id": 1,
+ },
+ {
+ "id": 2,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "编辑",
+ "value": "Update",
+ "api": "/api/system/menu/{id}/",
+ "method": 2,
+ "creator_id": 1,
+ "menu_id": 1,
+ },
+ {
+ "id": 3,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "新增",
+ "value": "Create",
+ "api": "/api/system/menu/",
+ "method": 1,
+ "creator_id": 1,
+ "menu_id": 1,
+ },
+ {
+ "id": 4,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "详情",
+ "value": "Retrieve",
+ "api": "/api/system/menu/{id}/",
+ "method": 0,
+ "creator_id": 1,
+ "menu_id": 1,
+ },
+ {
+ "id": 5,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "删除",
+ "value": "Delete",
+ "api": "/api/system/menu/{id}/",
+ "method": 3,
+ "creator_id": 1,
+ "menu_id": 1,
+ },
+ {
+ "id": 6,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "编辑",
+ "value": "Update",
+ "api": "/api/system/user/{id}/",
+ "method": 2,
+ "creator_id": 1,
+ "menu_id": 3,
+ },
+ {
+ "id": 7,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "查询",
+ "value": "Search",
+ "api": "/api/system/user/",
+ "method": 0,
+ "creator_id": 1,
+ "menu_id": 3,
+ },
+ {
+ "id": 8,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "详情",
+ "value": "Retrieve",
+ "api": "/api/system/user/{id}/",
+ "method": 0,
+ "creator_id": 1,
+ "menu_id": 3,
+ },
+ {
+ "id": 9,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "新增",
+ "value": "Create",
+ "api": "/api/system/user/",
+ "method": 1,
+ "creator_id": 1,
+ "menu_id": 3,
+ },
+ {
+ "id": 10,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "删除",
+ "value": "Delete",
+ "api": "/api/system/user/{id}/",
+ "method": 3,
+ "creator_id": 1,
+ "menu_id": 3,
+ },
+ {
+ "id": 11,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "编辑",
+ "value": "Update",
+ "api": "/api/system/role/{id}/",
+ "method": 2,
+ "creator_id": 1,
+ "menu_id": 4,
+ },
+ {
+ "id": 12,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "查询",
+ "value": "Search",
+ "api": "/api/system/role/",
+ "method": 0,
+ "creator_id": 1,
+ "menu_id": 4,
+ },
+ {
+ "id": 13,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "详情",
+ "value": "Retrieve",
+ "api": "/api/system/role/{id}/",
+ "method": 0,
+ "creator_id": 1,
+ "menu_id": 4,
+ },
+ {
+ "id": 14,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "新增",
+ "value": "Create",
+ "api": "/api/system/role/",
+ "method": 1,
+ "creator_id": 1,
+ "menu_id": 4,
+ },
+ {
+ "id": 15,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "删除",
+ "value": "Delete",
+ "api": "/api/system/role/{id}/",
+ "method": 3,
+ "creator_id": 1,
+ "menu_id": 4,
+ },
+ {
+ "id": 16,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "编辑",
+ "value": "Update",
+ "api": "/api/system/dept/{id}/",
+ "method": 2,
+ "creator_id": 1,
+ "menu_id": 5,
+ },
+ {
+ "id": 17,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "查询",
+ "value": "Search",
+ "api": "/api/system/dept/",
+ "method": 0,
+ "creator_id": 1,
+ "menu_id": 5,
+ },
+ {
+ "id": 18,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "详情",
+ "value": "Retrieve",
+ "api": "/api/system/dept/{id}/",
+ "method": 0,
+ "creator_id": 1,
+ "menu_id": 5,
+ },
+ {
+ "id": 19,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "新增",
+ "value": "Create",
+ "api": "/api/system/dept/",
+ "method": 1,
+ "creator_id": 1,
+ "menu_id": 5,
+ },
+ {
+ "id": 20,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "删除",
+ "value": "Delete",
+ "api": "/api/system/dept/{id}/",
+ "method": 3,
+ "creator_id": 1,
+ "menu_id": 5,
+ },
+ {
+ "id": 21,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "编辑",
+ "value": "Update",
+ "api": "/api/system/menu_button/{id}/",
+ "method": 2,
+ "creator_id": 1,
+ "menu_id": 7,
+ },
+ {
+ "id": 22,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "查询",
+ "value": "Search",
+ "api": "/api/system/menu_button/",
+ "method": 0,
+ "creator_id": 1,
+ "menu_id": 7,
+ },
+ {
+ "id": 23,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "新增",
+ "value": "Create",
+ "api": "/api/system/menu_button/",
+ "method": 1,
+ "creator_id": 1,
+ "menu_id": 7,
+ },
+ {
+ "id": 24,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "删除",
+ "value": "Delete",
+ "api": "/api/system/menu_button/{id}/",
+ "method": 3,
+ "creator_id": 1,
+ "menu_id": 7,
+ },
+ {
+ "id": 25,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "新增",
+ "value": "Create",
+ "api": "/api/system/button/",
+ "method": 1,
+ "creator_id": 1,
+ "menu_id": 8,
+ },
+ {
+ "id": 26,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "编辑",
+ "value": "Update",
+ "api": "/api/system/button/{id}/",
+ "method": 2,
+ "creator_id": 1,
+ "menu_id": 8,
+ },
+ {
+ "id": 27,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "查询",
+ "value": "Search",
+ "api": "/api/system/button/",
+ "method": 0,
+ "creator_id": 1,
+ "menu_id": 8,
+ },
+ {
+ "id": 28,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "删除",
+ "value": "Delete",
+ "api": "/api/system/button/{id}/",
+ "method": 3,
+ "creator_id": 1,
+ "menu_id": 8,
+ },
+ {
+ "id": 29,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "保存",
+ "value": "Save",
+ "api": "/api/system/role/{id}/",
+ "method": 2,
+ "creator_id": 1,
+ "menu_id": 6,
+ },
+ {
+ "id": 30,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "编辑",
+ "value": "Update",
+ "api": "/api/system/api_white_list/{id}/",
+ "method": 2,
+ "creator_id": 1,
+ "menu_id": 9,
+ },
+ {
+ "id": 31,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "查询",
+ "value": "Search",
+ "api": "/api/system/api_white_list/",
+ "method": 0,
+ "creator_id": 1,
+ "menu_id": 9,
+ },
+ {
+ "id": 32,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "详情",
+ "value": "Retrieve",
+ "api": "/api/system/api_white_list/{id}/",
+ "method": 0,
+ "creator_id": 1,
+ "menu_id": 9,
+ },
+ {
+ "id": 33,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "新增",
+ "value": "Create",
+ "api": "/api/system/api_white_list/",
+ "method": 1,
+ "creator_id": 1,
+ "menu_id": 9,
+ },
+ {
+ "id": 34,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "删除",
+ "value": "Delete",
+ "api": "/api/system/api_white_list/{id}/",
+ "method": 3,
+ "creator_id": 1,
+ "menu_id": 9,
+ },
+ {
+ "id": 35,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "编辑",
+ "value": "Update",
+ "api": "/api/system/dictionary/{id}/",
+ "method": 2,
+ "creator_id": 1,
+ "menu_id": 10,
+ },
+ {
+ "id": 36,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "查询",
+ "value": "Search",
+ "api": "/api/system/dictionary/",
+ "method": 0,
+ "creator_id": 1,
+ "menu_id": 10,
+ },
+ {
+ "id": 37,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "详情",
+ "value": "Retrieve",
+ "api": "/api/system/dictionary/{id}/",
+ "method": 0,
+ "creator_id": 1,
+ "menu_id": 10,
+ },
+ {
+ "id": 38,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "新增",
+ "value": "Create",
+ "api": "/api/system/dictionary/",
+ "method": 1,
+ "creator_id": 1,
+ "menu_id": 10,
+ },
+ {
+ "id": 39,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "删除",
+ "value": "Delete",
+ "api": "/api/system/dictionary/{id}/",
+ "method": 3,
+ "creator_id": 1,
+ "menu_id": 10,
+ },
+ {
+ "id": 40,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "编辑",
+ "value": "Update",
+ "api": "/api/system/area/{id}/",
+ "method": 2,
+ "creator_id": 1,
+ "menu_id": 11,
+ },
+ {
+ "id": 41,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "查询",
+ "value": "Search",
+ "api": "/api/system/area/",
+ "method": 0,
+ "creator_id": 1,
+ "menu_id": 11,
+ },
+ {
+ "id": 42,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "详情",
+ "value": "Retrieve",
+ "api": "/api/system/area/{id}/",
+ "method": 0,
+ "creator_id": 1,
+ "menu_id": 11,
+ },
+ {
+ "id": 43,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "新增",
+ "value": "Create",
+ "api": "/api/system/area/",
+ "method": 1,
+ "creator_id": 1,
+ "menu_id": 11,
+ },
+ {
+ "id": 44,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "删除",
+ "value": "Delete",
+ "api": "/api/system/area/{id}/",
+ "method": 3,
+ "creator_id": 1,
+ "menu_id": 11,
+ },
+ {
+ "id": 45,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "详情",
+ "value": "Retrieve",
+ "api": "/api/system/operation_log/{id}/",
+ "method": 0,
+ "creator_id": 1,
+ "menu_id": 16,
+ },
+ {
+ "id": 46,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "查询",
+ "value": "Search",
+ "api": "/api/system/operation_log/",
+ "method": 0,
+ "creator_id": 1,
+ "menu_id": 16,
+ },
+ {
+ "id": 47,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "导出",
+ "value": "Export",
+ "api": "/api/system/user/export/",
+ "method": 1,
+ "creator_id": 1,
+ "menu_id": 3,
+ },
+ {
+ "id": 48,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "导入",
+ "value": "Import",
+ "api": "/api/system/user/import/",
+ "method": 1,
+ "creator_id": 1,
+ "menu_id": 3,
+ },
+ {
+ "id": 49,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "详情",
+ "value": "Retrieve",
+ "api": "/api/system/file/{id}/",
+ "method": 0,
+ "creator_id": 1,
+ "menu_id": 13,
+ },
+ {
+ "id": 50,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "查询",
+ "value": "Search",
+ "api": "/api/system/file/",
+ "method": 0,
+ "creator_id": 1,
+ "menu_id": 13,
+ },
+ {
+ "id": 51,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "删除",
+ "value": "Delete",
+ "api": "/api/system/file/{id}/",
+ "method": 3,
+ "creator_id": 1,
+ "menu_id": 13,
+ },
+ {
+ "id": 52,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "编辑",
+ "value": "Update",
+ "api": "/api/system/file/{id}/",
+ "method": 1,
+ "creator_id": 1,
+ "menu_id": 13,
+ },
+ {
+ "id": 53,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "重置密码",
+ "value": "ResetPwd",
+ "api": "/api/system/user/reset_password/{id}/",
+ "method": 2,
+ "creator_id": 1,
+ "menu_id": 3,
+ },
+ {
+ "id": 54,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": "1",
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "查询",
+ "value": "Search",
+ "api": "/api/system/login_log/",
+ "method": 0,
+ "creator_id": 1,
+ "menu_id": 20,
+ },
+ {
+ "id": 55,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": "1",
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "详情",
+ "value": "Retrieve",
+ "api": "/api/system/login_log/{id}/",
+ "method": 0,
+ "creator_id": 1,
+ "menu_id": 20,
+ },
+ {
+ "id": 56,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "保存",
+ "value": "Save",
+ "api": "/api/system/role/{id}/",
+ "method": 2,
+ "creator_id": 1,
+ "menu_id": 4,
+ },
+]
+
+role_data = [
+ {
+ "id": 1,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "name": "管理员",
+ "key": "admin",
+ "sort": 1,
+ "status": 1,
+ "admin": 1,
+ "data_range": 3,
+ "menu": [ele.get("id") for ele in menu_data],
+ "permission": [ele.get("id") for ele in menu_button_data],
+ "remark": None,
+ "creator_id": 1,
+ }
+]
+
+staff_data = [
+ {
+ "password": "pbkdf2_sha256$260000$g17x5wlSiW1FZAh1Eudchw$ZeSAqj3Xak0io8v/pmPW0BX9EX5R2zFXDwbbD68oBFk=",
+ "last_login": None,
+ "is_superuser": 1,
+ "first_name": "",
+ "last_name": "",
+ "is_staff": 1,
+ "is_active": 1,
+ "id": 1,
+ "description": None,
+ "modifier": "1",
+ "dept_belong_id": 1,
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "username": "superadmin",
+ "email": "dvadmin@django-vue-admin.com",
+ "mobile": "13333333333",
+ "avatar": None,
+ "name": "超级管理员",
+ "gender": 1,
+ "creator_id": None,
+ "dept_id": 1,
+ },
+ {
+ "password": "pbkdf2_sha256$260000$g17x5wlSiW1FZAh1Eudchw$ZeSAqj3Xak0io8v/pmPW0BX9EX5R2zFXDwbbD68oBFk=",
+ "last_login": None,
+ "is_superuser": 0,
+ "first_name": "",
+ "last_name": "",
+ "is_staff": 1,
+ "is_active": 1,
+ "id": 2,
+ "description": "",
+ "modifier": "1",
+ "dept_belong_id": "",
+ "update_datetime": datetime.datetime.now(),
+ "create_datetime": datetime.datetime.now(),
+ "username": "admin",
+ "email": "dvadmin@django-vue-admin.com",
+ "mobile": "13333333333",
+ "avatar": "",
+ "name": "管理员",
+ "gender": 1,
+ "creator_id": None,
+ "dept_id": 1,
+ "role": [1],
+ },
+]
diff --git a/backend/dvadmin/system/util/initialize.py b/backend/dvadmin/system/util/initialize.py
new file mode 100644
index 0000000..fb82d09
--- /dev/null
+++ b/backend/dvadmin/system/util/initialize.py
@@ -0,0 +1,91 @@
+# 初始化
+import os
+
+import django
+
+from dvadmin.utils.core_initialize import CoreInitialize
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "application.settings")
+django.setup()
+
+from dvadmin.system.models import (
+ Dept,
+ Button,
+ Menu,
+ MenuButton,
+ Role,
+ Users,
+ Dictionary,
+)
+
+from .init_data import (
+ dept_data,
+ button_data,
+ menu_data,
+ menu_button_data,
+ role_data,
+ staff_data,
+)
+
+
+class Initialize(CoreInitialize):
+ creator_id = 1
+
+ def init_dept(self):
+ """
+ 初始化部门信息
+ """
+ self.dept_data = dept_data
+ self.save(Dept, self.dept_data, "部门信息")
+
+ def init_button(self):
+ """
+ 初始化按钮表
+ """
+ self.button_data = button_data
+ self.save(Button, self.button_data, "权限表标识")
+
+ def init_menu(self):
+ """
+ 初始化菜单表
+ """
+ self.menu_data = menu_data
+ self.save(Menu, self.menu_data, "菜单表")
+
+ def init_menu_button(self):
+ """
+ 初始化菜单按钮表
+ """
+ self.menu_button_data = menu_button_data
+ self.save(MenuButton, self.menu_button_data, "菜单权限表")
+
+ def init_role(self):
+ """
+ 初始化角色表
+ """
+ data = role_data
+ self.save(Role, data, "角色表")
+
+ def init_users(self):
+ """
+ 初始化用户表
+ """
+ data = staff_data
+ self.save(Users, data, "用户表", no_reset=False)
+
+ def run(self):
+ self.init_dept()
+ self.init_button()
+ self.init_menu()
+ self.init_menu_button()
+ self.init_role()
+ self.init_users()
+
+
+# 项目init 初始化,默认会执行 main 方法进行初始化
+def main(reset=False):
+ Initialize(reset).run()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/backend/dvadmin/utils/serializers.py b/backend/dvadmin/utils/serializers.py
index c6af51c..09cf50c 100644
--- a/backend/dvadmin/utils/serializers.py
+++ b/backend/dvadmin/utils/serializers.py
@@ -17,37 +17,46 @@ from dvadmin.system.models import Users
from django_restql.mixins import DynamicFieldsMixin
-
-class CustomModelSerializer(DynamicFieldsMixin,ModelSerializer):
+class CustomModelSerializer(DynamicFieldsMixin, ModelSerializer):
"""
增强DRF的ModelSerializer,可自动更新模型的审计字段记录
(1)self.request能获取到rest_framework.request.Request对象
"""
+
# 修改人的审计字段名称, 默认modifier, 继承使用时可自定义覆盖
- modifier_field_id = 'modifier'
+ modifier_field_id = "modifier"
modifier_name = serializers.SerializerMethodField(read_only=True)
def get_modifier_name(self, instance):
- if not hasattr(instance, 'modifier'):
+ if not hasattr(instance, "modifier"):
return None
- queryset = Users.objects.filter(username=instance.modifier).values_list('name', flat=True).first()
+ queryset = (
+ Users.objects.filter(id=instance.modifier)
+ .values_list("name", flat=True)
+ .first()
+ )
if queryset:
return queryset
return None
# 创建人的审计字段名称, 默认creator, 继承使用时可自定义覆盖
- creator_field_id = 'creator'
- creator_name = serializers.SlugRelatedField(slug_field="name", source="creator", read_only=True)
+ creator_field_id = "creator"
+ creator_name = serializers.SlugRelatedField(
+ slug_field="name", source="creator", read_only=True
+ )
# 数据所属部门字段
- dept_belong_id_field_name = 'dept_belong_id'
+ dept_belong_id_field_name = "dept_belong_id"
# 添加默认时间返回格式
- create_datetime = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False, read_only=True)
- update_datetime = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False)
-
+ create_datetime = serializers.DateTimeField(
+ format="%Y-%m-%d %H:%M:%S", required=False, read_only=True
+ )
+ update_datetime = serializers.DateTimeField(
+ format="%Y-%m-%d %H:%M:%S", required=False
+ )
def __init__(self, instance=None, data=empty, request=None, **kwargs):
super().__init__(instance, data, **kwargs)
- self.request: Request = request or self.context.get('request', None)
+ self.request: Request = request or self.context.get("request", None)
def save(self, **kwargs):
return super().save(**kwargs)
@@ -60,30 +69,36 @@ class CustomModelSerializer(DynamicFieldsMixin,ModelSerializer):
if self.creator_field_id in self.fields.fields:
validated_data[self.creator_field_id] = self.request.user
- if self.dept_belong_id_field_name in self.fields.fields and validated_data.get(
- self.dept_belong_id_field_name, None) is None:
- validated_data[self.dept_belong_id_field_name] = getattr(self.request.user, 'dept_id', None)
+ if (
+ self.dept_belong_id_field_name in self.fields.fields
+ and validated_data.get(self.dept_belong_id_field_name, None) is None
+ ):
+ validated_data[self.dept_belong_id_field_name] = getattr(
+ self.request.user, "dept_id", None
+ )
return super().create(validated_data)
def update(self, instance, validated_data):
if self.request:
if hasattr(self.instance, self.modifier_field_id):
- setattr(self.instance, self.modifier_field_id, self.get_request_user_id())
+ setattr(
+ self.instance, self.modifier_field_id, self.get_request_user_id()
+ )
return super().update(instance, validated_data)
def get_request_username(self):
- if getattr(self.request, 'user', None):
- return getattr(self.request.user, 'username', None)
+ if getattr(self.request, "user", None):
+ return getattr(self.request.user, "username", None)
return None
def get_request_name(self):
- if getattr(self.request, 'user', None):
- return getattr(self.request.user, 'name', None)
+ if getattr(self.request, "user", None):
+ return getattr(self.request.user, "name", None)
return None
def get_request_user_id(self):
- if getattr(self.request, 'user', None):
- return getattr(self.request.user, 'id', None)
+ if getattr(self.request, "user", None):
+ return getattr(self.request.user, "id", None)
return None
# @cached_property
@@ -132,4 +147,3 @@ class CustomModelSerializer(DynamicFieldsMixin,ModelSerializer):
# fields.pop(field, None)
#
# return fields
-
diff --git a/web/src/components/d2-container/components/d2-source.vue b/web/src/components/d2-container/components/d2-source.vue
index 2c85d5a..b81a8e9 100644
--- a/web/src/components/d2-container/components/d2-source.vue
+++ b/web/src/components/d2-container/components/d2-source.vue
@@ -3,8 +3,9 @@
v-if="show"
class="d2-source"
:class="{ 'd2-source--active': isActive }"
- @click="handleClick">
- 本页源码
+ @click="handleClick"
+ >
+ 本页源码
@@ -51,11 +52,11 @@ export default {
$paddingLR: 15px;
$paddingTB: 7px;
$fontSize: 12px;
- $rightOuter: $paddingLR / 2;
+ $rightOuter: calc($paddingLR / 2);
opacity: 0;
position: fixed;
z-index: 9999;
- right: - $borderRadius - $rightOuter;
+ right: -$borderRadius - $rightOuter;
bottom: 20px;
font-size: $fontSize;
line-height: $fontSize;
@@ -63,17 +64,17 @@ export default {
border-radius: $borderRadius;
padding: $paddingTB $paddingLR;
padding-right: $borderRadius + $paddingLR;
- background-color: rgba(#000, .7);
+ background-color: rgba(#000, 0.7);
border: 1px solid #000;
- color: #FFF;
- transition: all .3s;
+ color: #fff;
+ transition: all 0.3s;
@extend %unable-select;
&.d2-source--active {
opacity: 1;
}
&:hover {
- right: - $borderRadius;
- background-color: rgba(#000, .9);
+ right: -$borderRadius;
+ background-color: rgba(#000, 0.9);
}
}
diff --git a/web/src/views/system/login/page.vue b/web/src/views/system/login/page.vue
index d0bb2fe..fc095eb 100644
--- a/web/src/views/system/login/page.vue
+++ b/web/src/views/system/login/page.vue
@@ -86,14 +86,15 @@
注册用户
-->
-
+ 快速选择用户(限dev环境)
+
-
- {{ time }}
-
+ {{ time }}
-
+
-
+

@@ -38,11 +25,7 @@
size="default"
>
-
+
@@ -56,42 +39,27 @@
-
-
+
+
-
+
-
- 登录
-
+ 登录
+ -->
快速选择用户(限dev环境)
@@ -109,12 +77,9 @@
新增
+ 新增
+
-
+
@@ -57,40 +57,40 @@ export default {
name: 'user',
mixins: [d2CrudPlus.crud],
data () {
- var validatePass = (rule, value, callback) => {
- const pwdRegex = new RegExp('(?=.*[0-9])(?=.*[a-zA-Z]).{8,30}')
- if (value === '') {
- callback(new Error('请输入密码'))
- } else if (!pwdRegex.test(value)) {
- callback(new Error('您的密码复杂度太低(密码中必须包含字母、数字)'))
- } else {
- if (this.resetPwdForm.pwd2 !== '') {
- this.$refs.resetPwdForm.validateField('pwd2')
- }
- callback()
- }
- }
- var validatePass2 = (rule, value, callback) => {
- if (value === '') {
- callback(new Error('请再次输入密码'))
- } else if (value !== this.resetPwdForm.pwd) {
- callback(new Error('两次输入密码不一致!'))
- } else {
- callback()
- }
- }
- return {
- dialogFormVisible: false,
- resetPwdForm: {
- id: null,
- pwd: null,
- pwd2: null
- },
- passwordRules: {
- pwd: [{ required: true, message: '必填项' }, { validator: validatePass, trigger: 'blur' }],
- pwd2: [{ required: true, message: '必填项' }, { validator: validatePass2, trigger: 'blur' }]
- }
- }
+ // var validatePass = (rule, value, callback) => {
+ // const pwdRegex = new RegExp('(?=.*[0-9])(?=.*[a-zA-Z]).{8,30}')
+ // if (value === '') {
+ // callback(new Error('请输入密码'))
+ // } else if (!pwdRegex.test(value)) {
+ // callback(new Error('您的密码复杂度太低(密码中必须包含字母、数字)'))
+ // } else {
+ // if (this.resetPwdForm.pwd2 !== '') {
+ // this.$refs.resetPwdForm.validateField('pwd2')
+ // }
+ // callback()
+ // }
+ // }
+ // var validatePass2 = (rule, value, callback) => {
+ // if (value === '') {
+ // callback(new Error('请再次输入密码'))
+ // } else if (value !== this.resetPwdForm.pwd) {
+ // callback(new Error('两次输入密码不一致!'))
+ // } else {
+ // callback()
+ // }
+ // }
+ // return {
+ // dialogFormVisible: false,
+ // resetPwdForm: {
+ // id: null,
+ // pwd: null,
+ // pwd2: null
+ // },
+ // passwordRules: {
+ // pwd: [{ required: true, message: '必填项' }, { validator: validatePass, trigger: 'blur' }],
+ // pwd2: [{ required: true, message: '必填项' }, { validator: validatePass2, trigger: 'blur' }]
+ // }
+ // }
},
methods: {
getCrudOptions () {
@@ -108,35 +108,40 @@ export default {
delRequest (row) {
return api.DelObj(row.id)
},
- // 重置密码弹框
- resetPwd ({ row }) {
- this.dialogFormVisible = true
- this.resetPwdForm.id = row.id
- },
- // 重置密码确认
- resetPwdSubmit () {
- const that = this
- that.$refs.resetPwdForm.validate((valid) => {
- if (valid) {
- const params = {
- id: that.resetPwdForm.id,
- newPassword: that.$md5(that.resetPwdForm.pwd),
- newPassword2: that.$md5(that.resetPwdForm.pwd2)
- }
- api.ResetPwd(params).then(res => {
- that.dialogFormVisible = false
- that.resetPwdForm = {
- id: null,
- pwd: null,
- pwd2: null
- }
- that.$message.success('修改成功')
- })
- } else {
- that.$message.error('表单校验失败,请检查')
- }
+ resetPassword (scope) {
+ api.ResetPwd(scope.row).then(res => {
+ this.$message.success('密码重置成功')
})
}
+ // // 重置密码弹框
+ // resetPwd ({ row }) {
+ // this.dialogFormVisible = true
+ // this.resetPwdForm.id = row.id
+ // },
+ // // 重置密码确认
+ // resetPwdSubmit () {
+ // const that = this
+ // that.$refs.resetPwdForm.validate((valid) => {
+ // if (valid) {
+ // const params = {
+ // id: that.resetPwdForm.id,
+ // newPassword: that.$md5(that.resetPwdForm.pwd),
+ // newPassword2: that.$md5(that.resetPwdForm.pwd2)
+ // }
+ // api.ResetPwd(params).then(res => {
+ // that.dialogFormVisible = false
+ // that.resetPwdForm = {
+ // id: null,
+ // pwd: null,
+ // pwd2: null
+ // }
+ // that.$message.success('修改成功')
+ // })
+ // } else {
+ // that.$message.error('表单校验失败,请检查')
+ // }
+ // })
+ // }
}
}
From b02b673e1b8a40c9127e05c73a2172ab77f9e170 Mon Sep 17 00:00:00 2001
From: Angelo
Date: Tue, 26 Apr 2022 15:03:35 +0800
Subject: [PATCH 08/92] perf(logger propagate): logger propagate & add
migrations/__init__.py files to .gitignore
---
backend/.gitignore | 4 ++--
backend/application/settings.py | 2 ++
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/backend/.gitignore b/backend/.gitignore
index c663045..3da4e06 100644
--- a/backend/.gitignore
+++ b/backend/.gitignore
@@ -88,11 +88,11 @@ ENV/
.idea/
*.db
.DS_Store
-__pycache__
-**/migrations
+**/migrations/*.py
!**/migrations/__init__.py
*.pyc
conf/
!conf/env.example.py
db.sqlite3
media/
+__pypackages__/
\ No newline at end of file
diff --git a/backend/application/settings.py b/backend/application/settings.py
index a57e956..b7371c1 100644
--- a/backend/application/settings.py
+++ b/backend/application/settings.py
@@ -231,10 +231,12 @@ LOGGING = {
"django": {
"handlers": ["console", "error", "file"],
"level": "INFO",
+ "propagate": False,
},
"scripts": {
"handlers": ["console", "error", "file"],
"level": "INFO",
+ "propagate": False,
},
# 数据库相关日志
"django.db.backends": {
From 7f0a46c7d7214ef2fc534e287faa38044b828768 Mon Sep 17 00:00:00 2001
From: Angelo
Date: Tue, 26 Apr 2022 15:38:35 +0800
Subject: [PATCH 09/92] refactor(frontend request params): #
---
web/src/install.js | 5 +++--
web/src/views/system/dept/crud.js | 4 ++--
web/src/views/system/dictionary/crud.js | 4 ++--
web/src/views/system/menu/crud.js | 11 +++++++----
web/src/views/system/user/crud.js | 8 ++++----
web/src/views/system/user/index.vue | 26 ++++++++++++-------------
6 files changed, 31 insertions(+), 27 deletions(-)
diff --git a/web/src/install.js b/web/src/install.js
index 0b895d7..5711513 100644
--- a/web/src/install.js
+++ b/web/src/install.js
@@ -273,7 +273,7 @@ Vue.prototype.commonEndColumns = function (param = {}) {
type: 'table-selector',
dict: {
cache: true,
- url: deptPrefix + '?limit=999&status=1',
+ url: deptPrefix,
isTree: true,
value: 'id', // 数据字典中value字段的属性名
label: 'name', // 数据字典中label字段的属性名
@@ -283,7 +283,8 @@ Vue.prototype.commonEndColumns = function (param = {}) {
component
}) => {
return request({
- url: url
+ url: url,
+ params: { limit: 999, status: 1 }
}).then(ret => {
return ret.data.data
})
diff --git a/web/src/views/system/dept/crud.js b/web/src/views/system/dept/crud.js
index 1ea0316..751b012 100644
--- a/web/src/views/system/dept/crud.js
+++ b/web/src/views/system/dept/crud.js
@@ -97,13 +97,13 @@ export const crudOptions = (vm) => {
type: 'cascader',
dict: {
cache: false,
- url: deptPrefix + '?limit=999&status=1',
+ url: deptPrefix,
isTree: true,
value: 'id', // 数据字典中value字段的属性名
label: 'name', // 数据字典中label字段的属性名
children: 'children', // 数据字典中children字段的属性名
getData: (url, dict) => { // 配置此参数会覆盖全局的getRemoteDictFunc
- return request({ url: url }).then(ret => {
+ return request({ url: url, params: { limit: 999, status: 1 } }).then(ret => {
const data = XEUtils.toArrayTree(ret.data.data, { parentKey: 'parent', strict: true })
return [{ id: '0', name: '根节点', children: data }]
})
diff --git a/web/src/views/system/dictionary/crud.js b/web/src/views/system/dictionary/crud.js
index 75cd14c..4cd44ee 100644
--- a/web/src/views/system/dictionary/crud.js
+++ b/web/src/views/system/dictionary/crud.js
@@ -98,13 +98,13 @@ export const crudOptions = (vm) => {
type: 'cascader',
dict: {
cache: false,
- url: dictionaryPrefix + '?status=1&limit=999',
+ url: dictionaryPrefix,
isTree: true,
value: 'id', // 数据字典中value字段的属性名
label: 'label', // 数据字典中label字段的属性名
children: 'children', // 数据字典中children字段的属性名
getData: (url, dict) => { // 配置此参数会覆盖全局的getRemoteDictFunc
- return request({ url: url }).then(ret => {
+ return request({ url: url, params: { limit: 999, status: 1 } }).then(ret => {
return [{ id: null, label: '根节点', children: XEUtils.toArrayTree(ret.data.data, { parentKey: 'parent', strict: true }) }]
})
}
diff --git a/web/src/views/system/menu/crud.js b/web/src/views/system/menu/crud.js
index 631976d..a781e93 100644
--- a/web/src/views/system/menu/crud.js
+++ b/web/src/views/system/menu/crud.js
@@ -27,7 +27,8 @@ export const crudOptions = (vm) => {
options: {
rowId: 'id',
height: '100%', // 表格高度100%, 使用toolbar必须设置
- highlightCurrentRow: false
+ highlightCurrentRow: false,
+ defaultExpandAll: true
},
rowHandle: {
view: {
@@ -129,14 +130,14 @@ export const crudOptions = (vm) => {
},
type: 'cascader',
dict: {
- url: menuPrefix + '?limit=999&status=1&is_catalog=1',
+ url: menuPrefix,
cache: false,
isTree: true,
value: 'id', // 数据字典中value字段的属性名
label: 'name', // 数据字典中label字段的属性名
children: 'children', // 数据字典中children字段的属性名
getData: (url, dict, { form, component }) => { // 配置此参数会覆盖全局的getRemoteDictFunc
- return request({ url: url }).then(ret => {
+ return request({ url: url, params: { limit: 999, status: 1, is_catalog: 1 } }).then(ret => {
const responseData = ret.data.data
const result = XEUtils.toArrayTree(responseData, { parentKey: 'parent', strict: true })
return [{ id: null, name: '根节点', children: result }]
@@ -457,6 +458,8 @@ export const crudOptions = (vm) => {
}
}
}
- ].concat(vm.commonEndColumns({ update_datetime: { showTable: false } }))
+ ].concat(vm.commonEndColumns({
+ update_datetime: { showTable: false }
+ }))
}
}
diff --git a/web/src/views/system/user/crud.js b/web/src/views/system/user/crud.js
index bdbb4c3..4619404 100644
--- a/web/src/views/system/user/crud.js
+++ b/web/src/views/system/user/crud.js
@@ -84,7 +84,6 @@ export const crudOptions = (vm) => {
{
title: 'ID',
key: 'id',
- width: 90,
disabled: true,
form: {
disabled: true
@@ -96,7 +95,7 @@ export const crudOptions = (vm) => {
search: {
disabled: false
},
- width: 140,
+ minWidth: 100,
type: 'input',
form: {
rules: [ // 表单校验规则
@@ -119,6 +118,7 @@ export const crudOptions = (vm) => {
{
title: '姓名',
key: 'name',
+ minWidth: 90,
search: {
disabled: false
},
@@ -167,9 +167,9 @@ export const crudOptions = (vm) => {
},
component: {
span: 12,
+ pagination: true,
props: { multiple: false },
elProps: {
- pagination: true,
columns: [
{
field: 'name',
@@ -306,9 +306,9 @@ export const crudOptions = (vm) => {
},
component: {
span: 12,
+ pagination: true,
props: { multiple: true },
elProps: {
- pagination: true,
columns: [
{
field: 'name',
diff --git a/web/src/views/system/user/index.vue b/web/src/views/system/user/index.vue
index f8b6239..c011c28 100644
--- a/web/src/views/system/user/index.vue
+++ b/web/src/views/system/user/index.vue
@@ -79,18 +79,18 @@ export default {
// callback()
// }
// }
- // return {
- // dialogFormVisible: false,
- // resetPwdForm: {
- // id: null,
- // pwd: null,
- // pwd2: null
- // },
- // passwordRules: {
- // pwd: [{ required: true, message: '必填项' }, { validator: validatePass, trigger: 'blur' }],
- // pwd2: [{ required: true, message: '必填项' }, { validator: validatePass2, trigger: 'blur' }]
- // }
- // }
+ return {
+ // dialogFormVisible: false,
+ // resetPwdForm: {
+ // id: null,
+ // pwd: null,
+ // pwd2: null
+ // },
+ // passwordRules: {
+ // pwd: [{ required: true, message: '必填项' }, { validator: validatePass, trigger: 'blur' }],
+ // pwd2: [{ required: true, message: '必填项' }, { validator: validatePass2, trigger: 'blur' }]
+ // }
+ }
},
methods: {
getCrudOptions () {
@@ -109,7 +109,7 @@ export default {
return api.DelObj(row.id)
},
resetPassword (scope) {
- api.ResetPwd(scope.row).then(res => {
+ api.ResetPwd(scope.row).then((res) => {
this.$message.success('密码重置成功')
})
}
From 807a5819f28939267e2a60b434efdc0b3a056bd9 Mon Sep 17 00:00:00 2001
From: Angelo
Date: Tue, 26 Apr 2022 16:36:42 +0800
Subject: [PATCH 10/92] fix(mobile regex): #
---
.../components/header-user/userinfo.vue | 23 +++++++++++++------
1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/web/src/layout/header-aside/components/header-user/userinfo.vue b/web/src/layout/header-aside/components/header-user/userinfo.vue
index d8d3fd2..c327ffb 100644
--- a/web/src/layout/header-aside/components/header-user/userinfo.vue
+++ b/web/src/layout/header-aside/components/header-user/userinfo.vue
@@ -28,10 +28,21 @@
:action="action"
:headers="headers"
:limit="1"
- :disabled="fileList.length===1"
- :on-success="handleAvatarSuccess">
-
-
+ :disabled="fileList.length === 1"
+ :on-success="handleAvatarSuccess"
+ >
+
@@ -159,9 +170,7 @@ export default {
},
userInforules: {
name: [{ required: true, message: '请输入昵称', trigger: 'blur' }],
- mobile: [
- { pattern: /^1[3|4|5|7|8]\d{9}$/, message: '请输入正确手机号' }
- ]
+ mobile: [{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确手机号' }]
},
userPasswordInfo: {
oldPassword: '',
From b3e4e858be9ed54f2838bc5a98e9d9058f7d6dae Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E5=BC=BA?= <1206709430@qq.com>
Date: Tue, 26 Apr 2022 21:12:00 +0800
Subject: [PATCH 11/92] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9A=E6=B7=BB?=
=?UTF-8?q?=E5=8A=A0=E7=94=A8=E6=88=B7=E7=B1=BB=E5=9E=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
web/src/config/button.js | 2 +
.../store/modules/d2admin/modules/account.js | 44 ++++++++++---------
web/src/views/system/button/api.js | 2 +-
web/src/views/system/user/crud.js | 24 ++++++++--
web/src/views/system/user/index.vue | 1 +
5 files changed, 48 insertions(+), 25 deletions(-)
diff --git a/web/src/config/button.js b/web/src/config/button.js
index 7687c15..246e91e 100644
--- a/web/src/config/button.js
+++ b/web/src/config/button.js
@@ -30,3 +30,5 @@ export const BUTTON_STATUS_NUMBER = getButtonSettings([{ label: '启用', value:
export const BUTTON_WHETHER_NUMBER = getButtonSettings([{ label: '是', value: 1 }, { label: '否', value: 0 }])
// 是 true/ 否 false
export const BUTTON_WHETHER_BOOL = getButtonSettings([{ label: '是', value: true }, { label: '否', value: false }])
+// 用户类型
+export const USER_TYPE = getButtonSettings([{ label: '后台用户', value: 0 }, { label: '前台用户', value: 1 }])
diff --git a/web/src/store/modules/d2admin/modules/account.js b/web/src/store/modules/d2admin/modules/account.js
index 2fdc0b1..e3f0d79 100644
--- a/web/src/store/modules/d2admin/modules/account.js
+++ b/web/src/store/modules/d2admin/modules/account.js
@@ -16,22 +16,24 @@ export default {
namespaced: true,
actions: {
/**
- * @description 登录
- * @param {Object} context
- * @param {Object} data
- * @param {Object} data username {String} 用户账号
- * @param {Object} data password {String} 密码
- * @param {Object} data route {Object} 登录成功后定向的路由对象 任何 vue-router 支持的格式
- * @param {Object} data request function 请求方法
+ * @description 登录
+ * @param {Object} context
+ * @param {Object} payload username {String} 用户账号
+ * @param {Object} payload password {String} 密码
+ * @param {Object} payload route {Object} 登录成功后定向的路由对象 任何 vue-router 支持的格式
*/
- async login ({ dispatch }, data) {
- let request = data.request
- if (request) {
- delete data.request
- } else {
- request = SYS_USER_LOGIN
- }
- let res = await request(data)
+ async login ({ dispatch }, {
+ username = '',
+ password = '',
+ captcha = '',
+ captchaKey = ''
+ } = {}) {
+ let res = await SYS_USER_LOGIN({
+ username,
+ password,
+ captcha,
+ captchaKey
+ })
// 设置 cookie 一定要存 uuid 和 token 两个 cookie
// 整个系统依赖这两个数据进行校验和存储
// uuid 是用户身份唯一标识 用户注册的时候确定 并且不可改变 不可重复
@@ -47,14 +49,14 @@ export default {
await dispatch('load')
},
/**
- * @description 注销用户并返回登录页面
- * @param {Object} context
- * @param {Object} payload confirm {Boolean} 是否需要确认
- */
+ * @description 注销用户并返回登录页面
+ * @param {Object} context
+ * @param {Object} payload confirm {Boolean} 是否需要确认
+ */
logout ({ commit, dispatch }, { confirm = false } = {}) {
/**
- * @description 注销
- */
+ * @description 注销
+ */
async function logout () {
await SYS_USER_LOGOUT({ refresh: util.cookies.get('refresh') }).then(() => {
// 删除cookie
diff --git a/web/src/views/system/button/api.js b/web/src/views/system/button/api.js
index c164a9b..aa26c5c 100644
--- a/web/src/views/system/button/api.js
+++ b/web/src/views/system/button/api.js
@@ -14,7 +14,7 @@ export function GetList (query) {
return request({
url: urlPrefix,
method: 'get',
- data: query
+ params: query
})
}
export function createObj (obj) {
diff --git a/web/src/views/system/user/crud.js b/web/src/views/system/user/crud.js
index 0e9a97b..8efe67d 100644
--- a/web/src/views/system/user/crud.js
+++ b/web/src/views/system/user/crud.js
@@ -1,5 +1,5 @@
import { request } from '@/api/service'
-import { BUTTON_STATUS_BOOL } from '@/config/button'
+import { BUTTON_STATUS_BOOL, USER_TYPE } from '@/config/button'
import { urlPrefix as deptPrefix } from '../dept/api'
export const crudOptions = (vm) => {
@@ -234,8 +234,26 @@ export const crudOptions = (vm) => {
}
},
component: { props: { color: 'auto' } } // 自动染色
- },
- {
+ }, {
+ title: '用户类型',
+ key: 'user_type',
+ search: {
+ value: 0,
+ disabled: false
+ },
+ width: 140,
+ type: 'select',
+ dict: {
+ data: USER_TYPE
+ },
+ form: {
+ show: false,
+ value: 0,
+ component: {
+ span: 12
+ }
+ }
+ }, {
title: '状态',
key: 'is_active',
search: {
diff --git a/web/src/views/system/user/index.vue b/web/src/views/system/user/index.vue
index b8d787f..7d8c3a2 100644
--- a/web/src/views/system/user/index.vue
+++ b/web/src/views/system/user/index.vue
@@ -94,6 +94,7 @@ export default {
},
methods: {
getCrudOptions () {
+ this.crud.searchOptions.form.user_type = 0
return crudOptions(this)
},
pageRequest (query) {
From c651e1bdf9cca4c360d6731728d0f7c19a4ed947 Mon Sep 17 00:00:00 2001
From: Angelo
Date: Tue, 26 Apr 2022 21:39:33 +0800
Subject: [PATCH 12/92] =?UTF-8?q?refactor(config):=20=E5=8F=82=E6=95=B0?=
=?UTF-8?q?=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
backend/application/settings.py | 4 ++++
backend/application/urls.py | 2 --
backend/conf/env.example.py | 24 +++++++++++++-----------
3 files changed, 17 insertions(+), 13 deletions(-)
diff --git a/backend/application/settings.py b/backend/application/settings.py
index b7371c1..bb5505c 100644
--- a/backend/application/settings.py
+++ b/backend/application/settings.py
@@ -360,3 +360,7 @@ ALL_MODELS_OBJECTS = [] # 所有app models 对象
REGISTER_PLUGINS = (
# ""
)
+
+# 初始化需要执行的列表,用来初始化后执行
+INITIALIZE_LIST = []
+INITIALIZE_RESET_LIST = []
diff --git a/backend/application/urls.py b/backend/application/urls.py
index ffd55e9..8fc4585 100644
--- a/backend/application/urls.py
+++ b/backend/application/urls.py
@@ -73,8 +73,6 @@ urlpatterns = (
path("api/captcha/", CaptchaView.as_view()),
path("api/captcha/status/", CaptchaStatusView.as_view()),
path("apiLogin/", ApiLogin.as_view()),
- # 业务路由
- # re_path(r'^api/app_route/', include('apps.app_name.urls')),
]
+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
+ static(settings.STATIC_URL, document_root=settings.STATIC_URL)
diff --git a/backend/conf/env.example.py b/backend/conf/env.example.py
index 9016d58..692c356 100644
--- a/backend/conf/env.example.py
+++ b/backend/conf/env.example.py
@@ -1,8 +1,19 @@
+import os
+
+from application.settings import BASE_DIR
+
# ================================================= #
# *************** mysql数据库 配置 *************** #
# ================================================= #
-# 数据库地址
-DATABASE_ENGINE = "django.db.backends.mysql"
+# 数据库 ENGINE ,默认演示使用 sqlite3 数据库,正式环境建议使用 mysql 数据库
+# sqlite3 设置
+DATABASE_ENGINE = "django.db.backends.sqlite3"
+DATABASE_NAME = os.path.join(BASE_DIR, "db.sqlite3")
+
+# 使用mysql时,改为此配置
+# DATABASE_ENGINE = "django.db.backends.mysql"
+# DATABASE_NAME = 'django-vue-admin' # mysql 时使用
+
# 数据库地址 改为自己数据库地址
DATABASE_HOST = "127.0.0.1"
# # 数据库端口
@@ -11,12 +22,9 @@ DATABASE_PORT = 3306
DATABASE_USER = "root"
# # 数据库密码
DATABASE_PASSWORD = "123456"
-# 数据库名
-DATABASE_NAME = "database_name"
# 表前缀
TABLE_PREFIX = "sys_"
-APP_PREFIX = "app_"
# ================================================= #
# ******** redis配置,无redis 可不进行配置 ******** #
# ================================================= #
@@ -27,8 +35,6 @@ APP_PREFIX = "app_"
# ****************** 功能 启停 ******************* #
# ================================================= #
DEBUG = False
-# 是否启用插件,不需要可以设置为False
-ENABLE_PLUGINS = False
# 启动登录详细概略获取(通过调用api获取ip详细地址)
ENABLE_LOGIN_ANALYSIS_LOG = True
# 是否启用登录验证码,不需要可以设置为False
@@ -43,7 +49,3 @@ ALLOWED_HOSTS = ["*"]
# 默认密码
DEFAULT_PASSWORD = "admin123456"
-
-# 初始化需要执行的列表,用来初始化后执行
-INITIALIZE_LIST = []
-INITIALIZE_RESET_LIST = []
From f8561b4ea14fb42581af191c622775941cf409cb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E5=BC=BA?= <1206709430@qq.com>
Date: Tue, 26 Apr 2022 21:40:41 +0800
Subject: [PATCH 13/92] =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=8F=98=E5=8C=96:=20?=
=?UTF-8?q?=E9=80=9A=E8=BF=87=E8=B0=83=E7=94=A8api=E8=8E=B7=E5=8F=96ip?=
=?UTF-8?q?=E8=AF=A6=E7=BB=86=E5=9C=B0=E5=9D=80=E6=94=B9=E4=B8=BAget?=
=?UTF-8?q?=E8=AF=B7=E6=B1=82=E6=96=B9=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
backend/conf/env.example.py | 4 +---
backend/dvadmin/utils/request_util.py | 2 +-
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/backend/conf/env.example.py b/backend/conf/env.example.py
index 9016d58..80b476c 100644
--- a/backend/conf/env.example.py
+++ b/backend/conf/env.example.py
@@ -27,9 +27,7 @@ APP_PREFIX = "app_"
# ****************** 功能 启停 ******************* #
# ================================================= #
DEBUG = False
-# 是否启用插件,不需要可以设置为False
-ENABLE_PLUGINS = False
-# 启动登录详细概略获取(通过调用api获取ip详细地址)
+# 启动登录详细概略获取(通过调用api获取ip详细地址。如果是内网,关闭即可)
ENABLE_LOGIN_ANALYSIS_LOG = True
# 是否启用登录验证码,不需要可以设置为False
CAPTCHA_STATE = False
diff --git a/backend/dvadmin/utils/request_util.py b/backend/dvadmin/utils/request_util.py
index 14414fb..0e2d1b1 100644
--- a/backend/dvadmin/utils/request_util.py
+++ b/backend/dvadmin/utils/request_util.py
@@ -190,7 +190,7 @@ def get_ip_analysis(ip):
}
if ip != 'unknown' and ip:
if getattr(settings, 'ENABLE_LOGIN_ANALYSIS_LOG', True):
- res = requests.post(url='https://ip.django-vue-admin.com/ip/analysis', data=json.dumps({"ip": ip}))
+ res = requests.get(url='https://ip.django-vue-admin.com/ip/analysis', params={"ip": ip})
if res.status_code == 200:
res_data = res.json()
if res_data.get('code') == 0:
From 7c521955ff03e05d2e3b66479a14505d659ea53e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E5=BC=BA?= <1206709430@qq.com>
Date: Thu, 28 Apr 2022 15:50:45 +0800
Subject: [PATCH 14/92] =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=8F=98=E5=8C=96:=20?=
=?UTF-8?q?=E9=85=8D=E7=BD=AE=E6=9B=B4=E6=96=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
backend/application/settings.py | 3 +++
backend/conf/env.example.py | 6 +++---
web/public/image/theme/chester/preview@2x.jpg | Bin 0 -> 23789 bytes
web/public/image/theme/element/preview@2x.jpg | Bin 0 -> 33648 bytes
web/public/image/theme/line/preview@2x.jpg | Bin 0 -> 230637 bytes
web/public/image/theme/star/preview@2x.jpg | Bin 0 -> 949168 bytes
.../theme/tomorrow-night-blue/preview@2x.jpg | Bin 0 -> 51621 bytes
web/public/image/theme/violet/preview@2x.jpg | Bin 0 -> 102694 bytes
web/src/views/system/user/crud.js | 4 ++--
9 files changed, 8 insertions(+), 5 deletions(-)
create mode 100644 web/public/image/theme/chester/preview@2x.jpg
create mode 100644 web/public/image/theme/element/preview@2x.jpg
create mode 100644 web/public/image/theme/line/preview@2x.jpg
create mode 100644 web/public/image/theme/star/preview@2x.jpg
create mode 100644 web/public/image/theme/tomorrow-night-blue/preview@2x.jpg
create mode 100644 web/public/image/theme/violet/preview@2x.jpg
diff --git a/backend/application/settings.py b/backend/application/settings.py
index bb5505c..0b78fca 100644
--- a/backend/application/settings.py
+++ b/backend/application/settings.py
@@ -364,3 +364,6 @@ REGISTER_PLUGINS = (
# 初始化需要执行的列表,用来初始化后执行
INITIALIZE_LIST = []
INITIALIZE_RESET_LIST = []
+# 表前缀
+TABLE_PREFIX = getattr(locals(), "TABLE_PREFIX", "dvadmin_")
+DEFAULT_PASSWORD = getattr(locals(), "DEFAULT_PASSWORD", "admin123456")
diff --git a/backend/conf/env.example.py b/backend/conf/env.example.py
index 00efd97..a764d35 100644
--- a/backend/conf/env.example.py
+++ b/backend/conf/env.example.py
@@ -24,7 +24,7 @@ DATABASE_USER = "root"
DATABASE_PASSWORD = "123456"
# 表前缀
-TABLE_PREFIX = "sys_"
+TABLE_PREFIX = "dvadmin_"
# ================================================= #
# ******** redis配置,无redis 可不进行配置 ******** #
# ================================================= #
@@ -37,8 +37,8 @@ TABLE_PREFIX = "sys_"
DEBUG = False
# 启动登录详细概略获取(通过调用api获取ip详细地址。如果是内网,关闭即可)
ENABLE_LOGIN_ANALYSIS_LOG = True
-# 是否启用登录验证码,不需要可以设置为False
-CAPTCHA_STATE = False
+# 是否启用登录验证码,不需要可以设置为False,线上环境建议开启
+CAPTCHA_STATE = True
# 登录接口 /api/token/ 是否需要验证码认证,用于测试,正式环境建议取消
LOGIN_NO_CAPTCHA_AUTH = True
# ================================================= #
diff --git a/web/public/image/theme/chester/preview@2x.jpg b/web/public/image/theme/chester/preview@2x.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..e743d6fdb7dcdfa532e9087e2bc5dc2a31adf541
GIT binary patch
literal 23789
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
Nfzc2EhXC{cn*gY(-H-qP
literal 0
HcmV?d00001
diff --git a/web/public/image/theme/element/preview@2x.jpg b/web/public/image/theme/element/preview@2x.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..8e68ab64b6c53b176931cf8150cc0faebad34f49
GIT binary patch
literal 33648
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
literal 0
HcmV?d00001
diff --git a/web/public/image/theme/line/preview@2x.jpg b/web/public/image/theme/line/preview@2x.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..a9ed0cf911aa72174eb03a6cbe15c19af47cdee7
GIT binary patch
literal 230637
zcmce;XH*nh*DYM#4NXo8NDxF2$x*VPtt15jCFdX+l$=3r4l0N!DgsJAAW3o(Nzw`i
zat1+il#HSXigD*?uG&?#_Fi+%HP`y}{?`=5rXJ+#1VLxd
z3PY68KjYU5#H8kL?;Z@HATsc42MGE#g%Nh~^Yc=Yknr#ow{!5k=qPUQd08UJ&Pzf{
zTv7s3J{ja?XYcOl$8*uq+0{dZcfGEWm&esXh1Wz@M^eX2)zQWEOo)%8L5QxQeTcig
zq66>A6Fka6N
zNncHabT06d3NPuR0s{lZ1CNP&`Z!BSDJm*TNJ>jcON)U|i1`M4_}K-CdHC}EK7yK~
zuf30}m!GSr2M>HiyNjOwek#0Rro>CQ?4_gg=fMBt-MV}kzAog`zJB_S|4ie5{IsuO
zu$QBRzN4?FzmL5m_&DG1FN1sce?JlYK`Cq
z9PRu(eGEN4Fa3Uc=UqJgJbhg}z2HYB#be^?;ouqQ3*TANL>+xx0~{SRd^|7nAh$-z
z^?x|My42~@V4_ms^peQbkIAU39g~t*msC4-N>)*dm-JnS|KYMp-^{J%f2~3Eh^;~n1h9Hgzdk_MA=Ll-K>sr^e+KF6
zXcP+k75w}2hyT|%zX%W$C7A*R9)n_n&`c-{6Y5tpYCl-wXcRd(`k&>G#-PZ^u@scl
zR5akX7zq6Q&mU1}4EQ4@6$LdTxFj+R6*UDlB_%Z$gE|ahP-rr8rhVAMQl~D2|INFf
zV#Ch6>}8KMA2a3ssnZva9g)%hOVvQl(7}&|%HH?-!zY#ete<=$;+p%_sk55;WE}?&
zm?Uz{8u=e(V}FoY@#V&=na%j@s@LTMavDxI1p*a&=ca-8vF{+COai1P!
zma86-Vg2isZ^Xj`_E{B8YW@611BMPyD%se7jX<;*a9}136Lb>#@ey-?+i5vXQkr;w
z&{hIcJtlghhVtCe|`g^4r{#9ie7HFe=hzRA5a}v_lgWx_96B{9UJSPC-JYoVY-$%nsN!<
zz;IlWR!O$T7sbdQsZlL%%S%?NBp>8!{f$Qr;=s#HI@AZD1RO~4mrHHN;8!IoT;kD)NBEoH$&5S5jGU2!-gq`r6C$Ga4h%IY}d
zvJb7q?O`i~kx<%v&R+MB7J|sq7v%-^L&w*=5hp6%Wpbjvbgc7t1#!M*}
zRT^=0V1f)16F%T*XA`6BJtY|m#
ze7cO%J|Z3tlC}w^m-U2Mgd!vkM;n1zK@jgRNWDhkJvk5j1FhU<5N9(vSfK~Li?zHV
z@aE9g<4v(C)YeZo$7zb374{8!I)6f$LQ=ljfmunvpzE~9*Gj9wRO!QrAC+_&XpEC%
zq^Cyj-ol4
zwWBq)5C($!QMs7&%T
zQ;9pkRvi5z?JK+IwiL>i#n5Bxs;wAC7nwN9;=PDNL0S^76k^Gbkl2X|K;PL1gu@SKeVCLi_4^HY>)_<_){!lJs`|g>QA8&SSP82TO#TLPy$~rK%rM
zp8CX|0rm(5x{qTBB=}4NPumRRu
zmAL?!hjGcNx>6Zx0`h~*B!n`5B>fp>3kiMx`Av}Hye#BOfY9Q8W{Gz)0pc6AZ$K#Lmuuf}n)G)(ED4t6u2U_oz=2!ZF@&<>jrL|qj{%Pin1*ZUg(;w-|CmUbB8T&Le_;`*d!6u9e(Ys3<$upB-El7?MNo_PIgiZy(n##89easargpXbQbf
zxpVc$LyE-p8eG)A+RZ>qXu0Y+6t(Z#sSnRb#&I$kT3PQaDpJVD6I0W+nb6i6caPU6
z*54y;u4>RxzZoIMH_m1QtTu`VKDUUT3FNB
z%NO~@me8gc3fMM;cMNy>oip!I!M0&*x~`|OwNg!}M0U}(N`vg%S9i{SIx{r>_HoK<
zi8&gu_+P!8`>}SOzRo