Merge branch 'dvadmin-liqianglog' of https://gitee.com/liqianglog/django-vue-admin into dvadmin-dev

# Conflicts:
#	dvadmin-ui/src/store/modules/permission.js
pull/26/MERGE
李强 2021-05-02 19:28:25 +08:00
commit dc57574e55
12 changed files with 90 additions and 31 deletions

View File

@ -50,9 +50,9 @@ github地址[https://github.com/liqianglog/django-vue-admin](https://github.c
## 在线体验 ## 在线体验
演示地址:[https://demo.django-vue-admin.com/](https://demo.django-vue-admin.com/) 账号admin 密码123456 演示地址:[http://demo.django-vue-admin.com/](http://demo.django-vue-admin.com/) 账号admin 密码123456
文档地址:[https://django-vue-admin.com/](https://django-vue-admin.com/) 文档地址:[http://django-vue-admin.com/](http://django-vue-admin.com/)
## 前端 ## 前端

View File

@ -48,19 +48,22 @@ class MonitorModelViewSet(CustomModelViewSet):
""" """
pk = kwargs.get("pk") pk = kwargs.get("pk")
queryset = self.filter_queryset(self.get_queryset()) queryset = self.filter_queryset(self.get_queryset())
queryset = queryset.filter(server__id=pk).order_by("-create_datetime") queryset = queryset.filter(server__id=pk).order_by("create_datetime")
# 间隔取值 # 间隔取值
queryset_count = queryset.count() queryset_count = queryset.count()
Interval_num = 1 if queryset_count < 200 else int(queryset_count / 100) Interval_num = 1 if queryset_count < 200 else int(queryset_count / 100)
queryset = queryset.values('cpu_sys', 'mem_num', 'mem_sys')[::Interval_num][:100] queryset = queryset.values('cpu_sys', 'mem_num', 'mem_sys', 'create_datetime')[::Interval_num][:100]
data = { data = {
"cpu": [], "cpu": [],
"memory": [], "memory": [],
"datetime": [],
} }
for ele in queryset: for ele in queryset:
data["cpu"].append(float(ele.get('cpu_sys', 0)) / 100) data["cpu"].append(round(float(ele.get('cpu_sys', 0)), 2))
data["memory"].append(float(ele.get('mem_num', 0)) and round(float(ele.get('mem_sys', 0)) / data["datetime"].append(ele.get('create_datetime').strftime('%Y-%m-%d %H:%M:%S'))
float(ele.get('mem_num', 0)), 4)) data["memory"].append(round(float(ele.get('mem_num', 0)), 4) and round(float(ele.get('mem_sys', 0)) /
float(ele.get('mem_num', 0)) * 100,
2))
return SuccessResponse(data=data) return SuccessResponse(data=data)
def get_monitor_info(self, request: Request, *args, **kwargs): def get_monitor_info(self, request: Request, *args, **kwargs):

View File

@ -315,8 +315,9 @@ class ImportSerializerMixin:
# 导出模板 # 导出模板
if request.method == 'GET': if request.method == 'GET':
# 示例数据 # 示例数据
queryset = self.filter_queryset(self.get_queryset())
return SuccessResponse( return SuccessResponse(
export_excel_save_model(request, self.import_field_data.values(), [], '导入用户数据模板.xls')) export_excel_save_model(request, self.import_field_data.values(), [], f'导入{get_verbose_name(queryset)}模板.xls'))
updateSupport = request.data.get('updateSupport') updateSupport = request.data.get('updateSupport')
# 从excel中组织对应的数据结构然后使用序列化器保存 # 从excel中组织对应的数据结构然后使用序列化器保存
data = excel_to_data(request.data.get('file_url'), self.import_field_data) data = excel_to_data(request.data.get('file_url'), self.import_field_data)

View File

@ -33,6 +33,8 @@ class CustomModelSerializer(ModelSerializer):
return super().save(**kwargs) return super().save(**kwargs)
def create(self, validated_data): def create(self, validated_data):
if self.context.get('request'):
self.request = self.context.get('request')
if self.request: if self.request:
username = self.get_request_username() username = self.get_request_username()
if self.modifier_field_name in self.fields.fields: if self.modifier_field_name in self.fields.fields:

View File

@ -0,0 +1,28 @@
"""
重写校验器返回字段
"""
from rest_framework.validators import UniqueValidator, qs_exists
from vadmin.utils.exceptions import APIException
class CustomUniqueValidator(UniqueValidator):
"""
继承,重写必填字段的验证器结果,防止字段暴露
"""
def __call__(self, value, serializer_field):
# Determine the underlying model field name. This may not be the
# same as the serializer field name if `source=<>` is set.
field_name = serializer_field.source_attrs[-1]
# Determine the existing instance, if this is an update operation.
instance = getattr(serializer_field.parent, 'instance', None)
queryset = self.queryset
queryset = self.filter_queryset(value, queryset, field_name)
queryset = self.exclude_current_instance(queryset, instance)
if qs_exists(queryset):
raise APIException(message=self.message)
def __repr__(self):
return super().__repr__()

View File

@ -1,8 +1,8 @@
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from rest_framework import serializers from rest_framework import serializers
from rest_framework.validators import UniqueValidator
from ..op_drf.serializers import CustomModelSerializer from ..op_drf.serializers import CustomModelSerializer
from ..op_drf.validator import CustomUniqueValidator
from ..permission.models import Menu, Dept, Post, Role from ..permission.models import Menu, Dept, Post, Role
from ..system.models import MessagePush from ..system.models import MessagePush
@ -260,7 +260,8 @@ class UserProfileCreateUpdateSerializer(CustomModelSerializer):
post = PostSerializer(many=True, read_only=True) post = PostSerializer(many=True, read_only=True)
role = RoleSerializer(many=True, read_only=True) role = RoleSerializer(many=True, read_only=True)
username = serializers.CharField(required=True, max_length=150, username = serializers.CharField(required=True, max_length=150,
validators=[UniqueValidator(queryset=UserProfile.objects.all(), message="用戶已存在")], validators=[
CustomUniqueValidator(queryset=UserProfile.objects.all(), message="用戶已存在")],
error_messages={ error_messages={
"blank": "请输入用户名称", "blank": "请输入用户名称",
"required": "用户名称不能为空", "required": "用户名称不能为空",

View File

@ -121,3 +121,10 @@ INSERT INTO `permission_menu` (id, description, modifier, update_datetime, creat
INSERT INTO `permission_menu` (id, description, modifier, update_datetime, create_datetime, menuType, icon, name, orderNum, isFrame, web_path, component_path, interface_path, interface_method, perms, status, visible, isCache, creator_id, parentId_id, dept_belong_id) VALUES (88, '', 'admin', '2021-03-21 23:33:30.888568', '2021-03-21 23:33:30.888593', '2', NULL, '登录日志清空', 4, '1', NULL, NULL, '/admin/system/logininfor/clean/', 'DELETE', 'admin:system:logininfor:clean:delete', '1', '1', '1', 1, 62, '1'); INSERT INTO `permission_menu` (id, description, modifier, update_datetime, create_datetime, menuType, icon, name, orderNum, isFrame, web_path, component_path, interface_path, interface_method, perms, status, visible, isCache, creator_id, parentId_id, dept_belong_id) VALUES (88, '', 'admin', '2021-03-21 23:33:30.888568', '2021-03-21 23:33:30.888593', '2', NULL, '登录日志清空', 4, '1', NULL, NULL, '/admin/system/logininfor/clean/', 'DELETE', 'admin:system:logininfor:clean:delete', '1', '1', '1', 1, 62, '1');
INSERT INTO `permission_menu` (id, description, modifier, update_datetime, create_datetime, menuType, icon, name, orderNum, isFrame, web_path, component_path, interface_path, interface_method, perms, status, visible, isCache, creator_id, parentId_id, dept_belong_id) VALUES (90, '', 'admin', '2021-03-26 00:44:00.756139', '2021-03-26 00:43:14.390228', '2', NULL, '定时日志批量删除', 3, '1', NULL, NULL, '/admin/system/celery_log/{id}/', 'DELETE', 'admin:system:celery_log:{id}:delete', '1', '1', '1', 1, 79, '8'); INSERT INTO `permission_menu` (id, description, modifier, update_datetime, create_datetime, menuType, icon, name, orderNum, isFrame, web_path, component_path, interface_path, interface_method, perms, status, visible, isCache, creator_id, parentId_id, dept_belong_id) VALUES (90, '', 'admin', '2021-03-26 00:44:00.756139', '2021-03-26 00:43:14.390228', '2', NULL, '定时日志批量删除', 3, '1', NULL, NULL, '/admin/system/celery_log/{id}/', 'DELETE', 'admin:system:celery_log:{id}:delete', '1', '1', '1', 1, 79, '8');
INSERT INTO `permission_menu` (id, description, modifier, update_datetime, create_datetime, menuType, icon, name, orderNum, isFrame, web_path, component_path, interface_path, interface_method, perms, status, visible, isCache, creator_id, parentId_id, dept_belong_id) VALUES (91, '', 'admin', '2021-03-26 00:44:36.135658', '2021-03-26 00:44:36.135679', '2', NULL, '定时日志清空', 4, '1', NULL, NULL, '/admin/system/celery_log/clean/', 'DELETE', 'admin:system:celery_log:clean:delete', '1', '1', '1', 1, 79, '8'); INSERT INTO `permission_menu` (id, description, modifier, update_datetime, create_datetime, menuType, icon, name, orderNum, isFrame, web_path, component_path, interface_path, interface_method, perms, status, visible, isCache, creator_id, parentId_id, dept_belong_id) VALUES (91, '', 'admin', '2021-03-26 00:44:36.135658', '2021-03-26 00:44:36.135679', '2', NULL, '定时日志清空', 4, '1', NULL, NULL, '/admin/system/celery_log/clean/', 'DELETE', 'admin:system:celery_log:clean:delete', '1', '1', '1', 1, 79, '8');
INSERT INTO `permission_menu` (id, description, modifier, update_datetime, create_datetime, menuType, icon, name, orderNum, isFrame, web_path, component_path, interface_path, interface_method, perms, status, visible, isCache, creator_id, parentId_id, dept_belong_id) VALUES (92, '', 'admin', '2021-04-27 23:49:59.036636', '2021-04-27 23:44:54.512207', '1', 'server', '服务监控', 3, '1', '/monitor/server', 'vadmin/monitor/server/index', NULL, 'GET', NULL, '1', '1', '1', 1, 66, '1');
INSERT INTO `permission_menu` (id, description, modifier, update_datetime, create_datetime, menuType, icon, name, orderNum, isFrame, web_path, component_path, interface_path, interface_method, perms, status, visible, isCache, creator_id, parentId_id, dept_belong_id) VALUES (93, '', 'admin', '2021-04-27 23:57:46.633022', '2021-04-27 23:49:28.569029', '2', NULL, '服务监控查询', 1, '1', NULL, NULL, '/admin/monitor/server/', 'GET', 'admin:monitor:server:get', '1', '1', '1', 1, 92, '1');
INSERT INTO `permission_menu` (id, description, modifier, update_datetime, create_datetime, menuType, icon, name, orderNum, isFrame, web_path, component_path, interface_path, interface_method, perms, status, visible, isCache, creator_id, parentId_id, dept_belong_id) VALUES (94, '', 'admin', '2021-04-27 23:58:44.705142', '2021-04-27 23:58:13.384483', '2', NULL, '修改服务器信息', 2, '1', NULL, NULL, '/admin/monitor/server/{id}/', 'PUT', 'admin:monitor:server:{id}:put', '1', '1', '1', 1, 92, '1');
INSERT INTO `permission_menu` (id, description, modifier, update_datetime, create_datetime, menuType, icon, name, orderNum, isFrame, web_path, component_path, interface_path, interface_method, perms, status, visible, isCache, creator_id, parentId_id, dept_belong_id) VALUES (95, '', 'admin', '2021-04-27 23:59:29.530633', '2021-04-27 23:59:07.744938', '2', NULL, '修改监控信息', 3, '1', NULL, NULL, '/admin/monitor/monitor/enabled/', 'GET', 'admin:monitor:monitor:enabled:get', '1', '1', '1', 1, 92, '1');
INSERT INTO `permission_menu` (id, description, modifier, update_datetime, create_datetime, menuType, icon, name, orderNum, isFrame, web_path, component_path, interface_path, interface_method, perms, status, visible, isCache, creator_id, parentId_id, dept_belong_id) VALUES (96, '', 'admin', '2021-04-28 00:01:15.071889', '2021-04-27 23:59:48.612905', '2', NULL, '清空监控记录', 4, '1', NULL, NULL, '/admin/monitor/monitor/clean/', 'GET', 'admin:monitor:monitor:clean:get', '1', '1', '1', 1, 92, '1');
INSERT INTO `permission_menu` (id, description, modifier, update_datetime, create_datetime, menuType, icon, name, orderNum, isFrame, web_path, component_path, interface_path, interface_method, perms, status, visible, isCache, creator_id, parentId_id, dept_belong_id) VALUES (97, '', 'admin', '2021-05-02 19:12:06.813143', '2021-05-02 18:58:06.260280', '0', 'dashboard', '首页', 0, '1', '/home', NULL, NULL, 'GET', NULL, '1', '1', '1', 1, NULL, '1');
INSERT INTO `permission_menu` (id, description, modifier, update_datetime, create_datetime, menuType, icon, name, orderNum, isFrame, web_path, component_path, interface_path, interface_method, perms, status, visible, isCache, creator_id, parentId_id, dept_belong_id) VALUES (98, '', 'admin', '2021-05-02 19:10:34.233070', '2021-05-02 19:10:34.233125', '0', 'dashboard', '首页', 1, '1', 'index', 'index', NULL, 'GET', NULL, '1', '1', '1', 1, 97, '1');

View File

@ -56,14 +56,14 @@ export const constantRoutes = [
{ {
path: '', path: '',
component: Layout, component: Layout,
redirect: 'index', redirect: '/home/index',
children: [ children: [
{ // {
path: 'index', // path: 'index',
component: (resolve) => require(['@/views/index'], resolve), // component: (resolve) => require(['@/views/index'], resolve),
name: '首页', // name: '首页',
meta: { title: '首页', icon: 'dashboard', noCache: true, affix: true } // meta: { title: '首页', icon: 'dashboard', noCache: true, affix: true }
} // }
] ]
}, },
{ {

View File

@ -25,7 +25,7 @@ const permission = {
return new Promise(resolve => { return new Promise(resolve => {
// 向后端请求路由数据 // 向后端请求路由数据
getRouters().then(res => { getRouters().then(res => {
const data = handleTree(res.data, "id"); const data = handleTree(res.data, "id");
const sdata = JSON.parse(JSON.stringify(data)) const sdata = JSON.parse(JSON.stringify(data))
const rdata = JSON.parse(JSON.stringify(data)) const rdata = JSON.parse(JSON.stringify(data))
const sidebarRoutes = filterAsyncRouter(sdata) const sidebarRoutes = filterAsyncRouter(sdata)
@ -58,7 +58,11 @@ function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
} }
if (route.children != null && route.children && route.children.length) { if (route.children != null && route.children && route.children.length) {
route.children = filterAsyncRouter(route.children, route, type) route.children = filterAsyncRouter(route.children, route, type)
route.alwaysShow = true if (route.children.length === 1 && route.children[0].path === 'index') {
route.alwaysShow = false
} else {
route.alwaysShow = true
}
} else { } else {
delete route['children'] delete route['children']
delete route['redirect'] delete route['redirect']

View File

@ -74,14 +74,15 @@ export default {
serverInfo: VueTypes.object.isRequired, serverInfo: VueTypes.object.isRequired,
lineChartKey: VueTypes.string.isRequired, lineChartKey: VueTypes.string.isRequired,
chartTitle: VueTypes.string.isRequired, chartTitle: VueTypes.string.isRequired,
chartData: VueTypes.array.isRequired chartData: VueTypes.array.isRequired,
}, },
data() { data() {
return { return {
TIME_LIMIT_SETTING, TIME_LIMIT_SETTING,
timeLimit: DEFAULT_TIME, timeLimit: DEFAULT_TIME,
lineChartId: this.lineChartKey + 'Chart', lineChartId: this.lineChartKey + 'Chart',
lineChartData: this.chartData lineChartData: this.chartData,
lineChartTime: this.chartData
} }
}, },
@ -107,9 +108,14 @@ export default {
let barGraph = echarts.init(document.getElementById(this.lineChartId)) let barGraph = echarts.init(document.getElementById(this.lineChartId))
// //
barGraph.setOption({ barGraph.setOption({
tooltip: { tooltip : {
trigger: 'item', trigger: 'axis',
formatter: '{a} <br/>{b} : {c}' axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985',
}
}
}, },
legend: { legend: {
left: 'center', left: 'center',
@ -120,7 +126,8 @@ export default {
type: 'category', type: 'category',
name: 'x', name: 'x',
splitLine: { show: false }, splitLine: { show: false },
data: [] data:this.lineChartTime,
offset:20
}, },
grid: { grid: {
left: '1%', left: '1%',
@ -131,14 +138,19 @@ export default {
yAxis: { yAxis: {
type: 'value', type: 'value',
name: '使用率', name: '使用率',
axisLabel: {
show: true,
interval: 'auto',
formatter: '{value}%'
},
}, },
series: [ series: [
{ {
name: '使用率', name: '使用率',
type: 'line', type: 'line',
data: this.lineChartData data: this.lineChartData,
} }
] ],
}) })
}, },
changeTimeLimit(value) { changeTimeLimit(value) {
@ -146,8 +158,9 @@ export default {
this.getCurrentServerMonitorLogs() this.getCurrentServerMonitorLogs()
}, },
getCurrentServerMonitorLogs() { getCurrentServerMonitorLogs() {
getMonitorLogs(this.serverInfo.id,{ as: { 'create_datetime__range': this.currentTimeLimitSetting.timeRange } }).then(results => { getMonitorLogs(this.serverInfo.id, {as: JSON.stringify({create_datetime__range: this.currentTimeLimitSetting.timeRange})}).then(results => {
this.lineChartData = results.data[this.lineChartKey] this.lineChartData = results.data[this.lineChartKey]
this.lineChartTime = results.data["datetime"]
this.drawBar() this.drawBar()
}).catch(error => { }).catch(error => {
this.$message.warning(error.msg || `获取${this.chartTitle}数据失败!`) this.$message.warning(error.msg || `获取${this.chartTitle}数据失败!`)

View File

@ -115,7 +115,7 @@
<!-- 下方折线图 --> <!-- 下方折线图 -->
<div class="server-monitor-bottom"> <div class="server-monitor-bottom">
<!-- 折线图 --> <!-- 折线图 -->
<el-card class="box-card server-monitor-line-chart" v-for="(key, index) in Object.keys(lineChartData)" <el-card class="box-card server-monitor-line-chart" v-for="(key, index) in Object.keys(lineChartData).slice(0,2)"
:key="`${index}-${key}`"> :key="`${index}-${key}`">
<line-chart :line-chart-key="key" <line-chart :line-chart-key="key"
:server-info="currentServer" :server-info="currentServer"
@ -313,7 +313,7 @@ export default {
}, },
/** 获取监控日志信息 */ /** 获取监控日志信息 */
getCurrentServerMonitorLogs() { getCurrentServerMonitorLogs() {
getMonitorLogs(this.currentServer.id, { as: { 'create_datetime__range': this.timeRange } }).then(results => { getMonitorLogs(this.currentServer.id, { as: JSON.stringify( { 'create_datetime__range': this.timeRange })}).then(results => {
this.lineChartData = results.data this.lineChartData = results.data
}).catch(error => { }).catch(error => {
this.msgError(error.msg || '获取监控日志信息出错误!') this.msgError(error.msg || '获取监控日志信息出错误!')

View File

@ -117,7 +117,7 @@
<el-table-column label="字典名称" align="center" prop="dictName" :show-overflow-tooltip="true" /> <el-table-column label="字典名称" align="center" prop="dictName" :show-overflow-tooltip="true" />
<el-table-column label="字典类型" align="center" :show-overflow-tooltip="true"> <el-table-column label="字典类型" align="center" :show-overflow-tooltip="true">
<template slot-scope="scope"> <template slot-scope="scope">
<router-link :to="'/dict/type/data/' + scope.row.id" class="link-type"> <router-link :to="hasPermi(['system:dict:type:get']) ?'/dict/type/data/' + scope.row.id :'#'" class="link-type">
<span>{{ scope.row.dictType }}</span> <span>{{ scope.row.dictType }}</span>
</router-link> </router-link>
</template> </template>