操作日志前端完成
							parent
							
								
									38e09f556b
								
							
						
					
					
						commit
						f2f8fa241e
					
				|  | @ -118,7 +118,7 @@ USE_I18N = True | |||
| 
 | ||||
| USE_L10N = True | ||||
| 
 | ||||
| USE_TZ = True | ||||
| USE_TZ = False | ||||
| 
 | ||||
| # Static files (CSS, JavaScript, Images) | ||||
| # https://docs.djangoproject.com/en/1.11/howto/static-files/ | ||||
|  | @ -316,4 +316,4 @@ CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.math_challenge' | |||
| 
 | ||||
| API_LOG_ENABLE = True | ||||
| # API_LOG_METHODS = 'ALL' # ['POST', 'DELETE'] | ||||
| API_LOG_METHODS = ['POST', 'DELETE'] # ['POST', 'DELETE'] | ||||
| # API_LOG_METHODS = ['POST', 'DELETE'] # ['POST', 'DELETE'] | ||||
|  |  | |||
|  | @ -201,3 +201,12 @@ class CustomerModelViewLogger(ModelViewLogger): | |||
|         operator = self.user.username | ||||
|         model_name = getattr(self.model, '_meta').verbose_name | ||||
|         self.logger(f'{self.log_prefix}用户[username={operator}]删除{model_name}:[{instance}]') | ||||
| 
 | ||||
|     def handle_other(self, request: Request, instance: Model = None, *args, **kwargs): | ||||
|         """ | ||||
|         仅 其他 请求才会触发此方法 | ||||
|         """ | ||||
|         pass | ||||
|         operator = self.user.username | ||||
|         model_name = getattr(self.model, '_meta').verbose_name | ||||
|         self.logger(f'{self.log_prefix}用户[username={operator}]其他请求{model_name}:[{instance}]') | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ django中间件 | |||
| from django.conf import settings | ||||
| from django.utils.deprecation import MiddlewareMixin | ||||
| 
 | ||||
| from apps.vadmin.system.models import RequestLog | ||||
| from apps.vadmin.system.models import OperationLog | ||||
| from ..utils.request_util import get_request_ip, get_request_data, get_request_path, get_browser, get_os, \ | ||||
|     get_login_location | ||||
| 
 | ||||
|  | @ -39,7 +39,7 @@ class ApiLoggingMiddleware(MiddlewareMixin): | |||
|             'request_method': request.method, | ||||
|             'request_path': request.request_path, | ||||
|             'request_body': body, | ||||
|             'response_code': response.status_code, | ||||
|             'response_code': response.data.get('code'), | ||||
|             'request_location': get_login_location(request), | ||||
|             'request_os': get_os(request), | ||||
|             'request_browser': get_browser(request), | ||||
|  | @ -48,7 +48,7 @@ class ApiLoggingMiddleware(MiddlewareMixin): | |||
|             'json_result': {"code": response.data.get('code'), "msg": response.data.get('msg')}, | ||||
|             'request_modular': request.session.get('model_name'), | ||||
|         } | ||||
|         log = RequestLog(**info) | ||||
|         log = OperationLog(**info) | ||||
|         log.save() | ||||
| 
 | ||||
|     def process_request(self, request): | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ from rest_framework.request import Request | |||
| 
 | ||||
| from .response import SuccessResponse | ||||
| from ..utils.export_excel import excel_to_data, export_excel_save_model | ||||
| from ..utils.request_util import get_verbose_name | ||||
| 
 | ||||
| 
 | ||||
| class CreateModelMixin(mixins.CreateModelMixin): | ||||
|  | @ -35,10 +36,10 @@ class ListModelMixin(mixins.ListModelMixin): | |||
|     list_serializer_class = None | ||||
| 
 | ||||
|     def list(self, request: Request, *args, **kwargs): | ||||
|         queryset = self.filter_queryset(self.get_queryset()) | ||||
|         page = self.paginate_queryset(queryset) | ||||
|         if hasattr(self, 'handle_logging'): | ||||
|             self.handle_logging(request, *args, **kwargs) | ||||
|         queryset = self.filter_queryset(self.get_queryset()) | ||||
|         page = self.paginate_queryset(queryset) | ||||
|         if page is not None: | ||||
|             if getattr(self, 'values_queryset', None): | ||||
|                 return self.get_paginated_response(page) | ||||
|  | @ -298,8 +299,7 @@ class ImportSerializerMixin: | |||
|     # 导入序列化器 | ||||
|     import_serializer_class = None | ||||
| 
 | ||||
| 
 | ||||
|     @transaction.atomic # Django 事物 | ||||
|     @transaction.atomic  # Django 事物 | ||||
|     def importTemplate(self, request: Request, *args, **kwargs): | ||||
|         """ | ||||
|         用户导人模板 | ||||
|  | @ -358,4 +358,5 @@ class ExportSerializerMixin: | |||
|                 % self.__class__.__name__ | ||||
|         ) | ||||
|         data = self.export_serializer_class(self.get_queryset(), many=True).data | ||||
|         return SuccessResponse(export_excel_save_model(request, self.export_field_data, data, '导出用户数据.xls')) | ||||
|         return SuccessResponse(export_excel_save_model(request, self.export_field_data, data, | ||||
|                                                        f'导出{get_verbose_name(self.get_queryset())}.xls')) | ||||
|  |  | |||
|  | @ -72,7 +72,7 @@ class CustomAPIView(APIView): | |||
|         method = request.method.lower() | ||||
|         for view_logger in view_loggers: | ||||
|             view_logger.handle(request, *args, **kwargs) | ||||
|             logger_fun = getattr(view_logger, f'handle_{method}', None) | ||||
|             logger_fun = getattr(view_logger, f'handle_{method}', f'handle_other') | ||||
|             if logger_fun and isinstance(logger_fun, (FunctionType, MethodType)): | ||||
|                 logger_fun(request, *args, **kwargs) | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| import django_filters | ||||
| 
 | ||||
| from .models import LoginInfor | ||||
| from .models import LoginInfor, OperationLog | ||||
| from ..system.models import DictDetails, DictData, ConfigSettings, MessagePush, SaveFile | ||||
| 
 | ||||
| 
 | ||||
|  | @ -70,3 +70,15 @@ class LoginInforFilter(django_filters.rest_framework.FilterSet): | |||
|     class Meta: | ||||
|         model = LoginInfor | ||||
|         fields = '__all__' | ||||
| 
 | ||||
| 
 | ||||
| class OperationLogFilter(django_filters.rest_framework.FilterSet): | ||||
|     """ | ||||
|     操作日志 简单过滤器 | ||||
|     """ | ||||
|     request_modular = django_filters.CharFilter(lookup_expr='icontains') | ||||
|     creator_username = django_filters.CharFilter(field_name='creator__username', lookup_expr='icontains') | ||||
| 
 | ||||
|     class Meta: | ||||
|         model = OperationLog | ||||
|         fields = '__all__' | ||||
|  |  | |||
|  | @ -6,5 +6,5 @@ from ..models.save_file import SaveFile | |||
| from ..models.message_push import MessagePush | ||||
| from ..models.message_push import MessagePushUser | ||||
| from ..models.logininfor import LoginInfor | ||||
| from ..models.request_log import RequestLog | ||||
| from ..models.operation_log import OperationLog | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,12 +3,12 @@ from django.db.models import TextField, CharField, BooleanField | |||
| from ...op_drf.models import CoreModel | ||||
| 
 | ||||
| 
 | ||||
| class RequestLog(CoreModel): | ||||
| class OperationLog(CoreModel): | ||||
|     request_modular = CharField(max_length=64, verbose_name="请求模块", null=True, blank=True) | ||||
|     request_path = CharField(max_length=400, verbose_name="请求地址", null=True, blank=True) | ||||
|     request_body = TextField(verbose_name="请求参数", null=True, blank=True) | ||||
|     request_method = CharField(max_length=64, verbose_name="请求方式", null=True, blank=True) | ||||
|     request_msg = CharField(max_length=64, verbose_name="操作说明", null=True, blank=True) | ||||
|     request_msg = TextField(verbose_name="操作说明", null=True, blank=True) | ||||
|     request_ip = CharField(max_length=32, verbose_name="请求ip地址", null=True, blank=True) | ||||
|     request_browser = CharField(max_length=32, verbose_name="请求浏览器", null=True, blank=True) | ||||
|     response_code = CharField(max_length=32, verbose_name="响应状态码", null=True, blank=True) | ||||
|  | @ -1,6 +1,6 @@ | |||
| from rest_framework import serializers | ||||
| 
 | ||||
| from .models import LoginInfor | ||||
| from .models import LoginInfor, OperationLog | ||||
| from ..op_drf.serializers import CustomModelSerializer | ||||
| from ..system.models import DictData, DictDetails, ConfigSettings, SaveFile, MessagePush, MessagePushUser | ||||
| 
 | ||||
|  | @ -196,6 +196,7 @@ class ExportMessagePushSerializer(CustomModelSerializer): | |||
|             'id', 'title', 'content', 'message_type', 'is_reviewed', 'status', 'users', 'creator', 'modifier', | ||||
|             'update_datetime', 'create_datetime') | ||||
| 
 | ||||
| 
 | ||||
| class MessagePushUserSerializer(CustomModelSerializer): | ||||
|     """ | ||||
|     消息通知 用户查询简单序列化器 | ||||
|  | @ -208,7 +209,7 @@ class MessagePushUserSerializer(CustomModelSerializer): | |||
|     #     return UserProfileSerializer(obj.user.all(), many=True).data | ||||
|     # 返回这个消息是否已读 | ||||
|     def get_is_read(self, obj): | ||||
|         object = MessagePushUser.objects.filter(message_push=obj,user=self.context.get('request').user).first() | ||||
|         object = MessagePushUser.objects.filter(message_push=obj, user=self.context.get('request').user).first() | ||||
|         return object.is_read if object else False | ||||
| 
 | ||||
|     class Meta: | ||||
|  | @ -218,6 +219,7 @@ class MessagePushUserSerializer(CustomModelSerializer): | |||
|     def save(self, **kwargs): | ||||
|         return super().save(**kwargs) | ||||
| 
 | ||||
| 
 | ||||
| # ================================================= # | ||||
| # ************** 登录日志 序列化器  ************** # | ||||
| # ================================================= # | ||||
|  | @ -230,3 +232,30 @@ class LoginInforSerializer(CustomModelSerializer): | |||
|     class Meta: | ||||
|         model = LoginInfor | ||||
|         fields = "__all__" | ||||
| 
 | ||||
| 
 | ||||
| # ================================================= # | ||||
| # ************** 操作日志 序列化器  ************** # | ||||
| # ================================================= # | ||||
| 
 | ||||
| class OperationLogSerializer(CustomModelSerializer): | ||||
|     """ | ||||
|     操作日志 简单序列化器 | ||||
|     """ | ||||
|     creator_name = serializers.SlugRelatedField(slug_field="username", source="creator", read_only=True) | ||||
| 
 | ||||
|     class Meta: | ||||
|         model = OperationLog | ||||
|         fields = "__all__" | ||||
| 
 | ||||
| 
 | ||||
| class ExportOperationLogSerializer(CustomModelSerializer): | ||||
|     """ | ||||
|     导出 操作日志 简单序列化器 | ||||
|     """ | ||||
|     creator_name = serializers.SlugRelatedField(slug_field="username", source="creator", read_only=True) | ||||
|     class Meta: | ||||
|         model = OperationLog | ||||
|         fields = ('request_modular', 'request_path', 'request_body', 'request_method', 'request_msg', 'request_ip', | ||||
|                   'request_browser', 'response_code', 'request_location', 'request_os', 'json_result', 'status', | ||||
|                   'creator_name') | ||||
|  |  | |||
|  | @ -2,7 +2,8 @@ from django.urls import re_path | |||
| from rest_framework.routers import DefaultRouter | ||||
| 
 | ||||
| from ..system.views import DictDataModelViewSet, DictDetailsModelViewSet, \ | ||||
|     ConfigSettingsModelViewSet, SaveFileModelViewSet, MessagePushModelViewSet, LoginInforModelViewSet | ||||
|     ConfigSettingsModelViewSet, SaveFileModelViewSet, MessagePushModelViewSet, LoginInforModelViewSet, \ | ||||
|     OperationLogModelViewSet | ||||
| 
 | ||||
| router = DefaultRouter() | ||||
| router.register(r'dict/type', DictDataModelViewSet) | ||||
|  | @ -11,6 +12,8 @@ router.register(r'config', ConfigSettingsModelViewSet) | |||
| router.register(r'savefile', SaveFileModelViewSet) | ||||
| router.register(r'message', MessagePushModelViewSet) | ||||
| router.register(r'logininfor', LoginInforModelViewSet) | ||||
| router.register(r'operation_log', OperationLogModelViewSet) | ||||
| 
 | ||||
| urlpatterns = [ | ||||
|     re_path('dict/get/type/(?P<pk>.*)/', DictDetailsModelViewSet.as_view({'get': 'dict_details_list'})), | ||||
|     re_path('config/configKey/(?P<pk>.*)/', ConfigSettingsModelViewSet.as_view({'get': 'get_config_key'})), | ||||
|  | @ -30,5 +33,9 @@ urlpatterns = [ | |||
|     re_path('message/user_messages/', MessagePushModelViewSet.as_view({'get': 'get_user_messages', })), | ||||
|     # 改为已读 | ||||
|     re_path('message/is_read/(?P<pk>.*)/', MessagePushModelViewSet.as_view({'put': 'update_is_read', })), | ||||
|     # 清空操作日志 | ||||
|     re_path('operation_log/clean/', OperationLogModelViewSet.as_view({'delete': 'clean_all', })), | ||||
|     # 导出操作日志 | ||||
|     re_path('operation_log/export/', OperationLogModelViewSet.as_view({'get': 'export', })), | ||||
| ] | ||||
| urlpatterns += router.urls | ||||
|  |  | |||
|  | @ -1,18 +1,19 @@ | |||
| from django.db.models import Q | ||||
| from rest_framework.request import Request | ||||
| 
 | ||||
| from .models import LoginInfor | ||||
| from .models import LoginInfor, OperationLog | ||||
| from ..op_drf.filters import DataLevelPermissionsFilter | ||||
| from ..op_drf.viewsets import CustomModelViewSet | ||||
| from ..system.filters import DictDetailsFilter, DictDataFilter, ConfigSettingsFilter, MessagePushFilter, \ | ||||
|     SaveFileFilter, LoginInforFilter | ||||
|     SaveFileFilter, LoginInforFilter, OperationLogFilter | ||||
| from ..system.models import DictData, DictDetails, ConfigSettings, SaveFile, MessagePush | ||||
| from ..system.models import MessagePushUser | ||||
| from ..system.serializers import DictDataSerializer, DictDataCreateUpdateSerializer, DictDetailsSerializer, \ | ||||
|     DictDetailsCreateUpdateSerializer, DictDetailsListSerializer, ConfigSettingsSerializer, \ | ||||
|     ConfigSettingsCreateUpdateSerializer, SaveFileSerializer, SaveFileCreateUpdateSerializer, \ | ||||
|     ExportConfigSettingsSerializer, ExportDictDataSerializer, ExportDictDetailsSerializer, \ | ||||
|     MessagePushSerializer, MessagePushCreateUpdateSerializer, ExportMessagePushSerializer, LoginInforSerializer | ||||
|     MessagePushSerializer, MessagePushCreateUpdateSerializer, ExportMessagePushSerializer, LoginInforSerializer, \ | ||||
|     OperationLogSerializer, ExportOperationLogSerializer | ||||
| from ..utils.export_excel import export_excel_save_model | ||||
| from ..utils.response import SuccessResponse | ||||
| 
 | ||||
|  | @ -224,3 +225,28 @@ class LoginInforModelViewSet(CustomModelViewSet): | |||
|     filter_class = LoginInforFilter | ||||
|     extra_filter_backends = [DataLevelPermissionsFilter] | ||||
|     ordering = 'create_datetime'  # 默认排序 | ||||
| 
 | ||||
| 
 | ||||
| class OperationLogModelViewSet(CustomModelViewSet): | ||||
|     """ | ||||
|    操作日志 模型的CRUD视图 | ||||
|    """ | ||||
|     queryset = OperationLog.objects.all() | ||||
|     serializer_class = OperationLogSerializer | ||||
|     filter_class = OperationLogFilter | ||||
|     extra_filter_backends = [DataLevelPermissionsFilter] | ||||
|     ordering = '-create_datetime'  # 默认排序 | ||||
|     export_field_data = ['请求模块', '请求地址', '请求参数', '请求方式', '操作说明', '请求ip地址', | ||||
|                          '请求浏览器', '响应状态码', '操作地点', '操作系统', '返回信息', '响应状态', '操作用户名'] | ||||
|     export_serializer_class = ExportOperationLogSerializer | ||||
| 
 | ||||
|     def clean_all(self, request: Request, *args, **kwargs): | ||||
|         """ | ||||
|         清空操作日志 | ||||
|         :param request: | ||||
|         :param args: | ||||
|         :param kwargs: | ||||
|         :return: | ||||
|         """ | ||||
|         self.get_queryset().delete() | ||||
|         return SuccessResponse(msg="清空成功") | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ import traceback | |||
| from rest_framework import serializers, exceptions | ||||
| from rest_framework.views import set_rollback | ||||
| 
 | ||||
| from .request_util import get_verbose_name | ||||
| from .response import ErrorResponse | ||||
| 
 | ||||
| logger = logging.getLogger(__name__) | ||||
|  | @ -17,9 +18,9 @@ class APIException(Exception): | |||
|     """ | ||||
| 
 | ||||
|     def __init__(self, code=201, message='API异常', args=('API异常',)): | ||||
|         self.args = args | ||||
|         self.code = code | ||||
|         self.message = message | ||||
|         args = args | ||||
|         code = code | ||||
|         message = message | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return self.message | ||||
|  | @ -36,7 +37,7 @@ class FrameworkException(Exception): | |||
| 
 | ||||
|     def __init__(self, message='框架异常', *args: object, **kwargs: object) -> None: | ||||
|         super().__init__(*args, **kwargs) | ||||
|         self.message = message | ||||
|         message = message | ||||
| 
 | ||||
|     def __str__(self) -> str: | ||||
|         return f"{self.message}" | ||||
|  | @ -64,6 +65,9 @@ def op_exception_handler(ex, context): | |||
|     """ | ||||
|     msg = '' | ||||
|     code = '201' | ||||
|     request = context.get('request') | ||||
|     request.session['model_name'] = get_verbose_name(view=context.get('view')) | ||||
| 
 | ||||
|     if isinstance(ex, AuthenticationFailed): | ||||
|         code = 401 | ||||
|         msg = ex.detail | ||||
|  |  | |||
|  | @ -172,3 +172,21 @@ def get_login_location(request, *args, **kwargs): | |||
|         content = r.content.decode('GBK') | ||||
|         return content.replace('\r', '').replace('\n', '') | ||||
|     return "" | ||||
| 
 | ||||
| 
 | ||||
| def get_verbose_name(queryset=None, view=None, model=None): | ||||
|     """ | ||||
|     获取 verbose_name | ||||
|     :param request: | ||||
|     :param view: | ||||
|     :return: | ||||
|     """ | ||||
|     if queryset and hasattr(queryset, 'model'): | ||||
|         model = queryset.model | ||||
|     elif view and hasattr(view.get_queryset(), 'model'): | ||||
|         model = view.get_queryset().model | ||||
|     elif view and hasattr(view.get_serializer(), 'Meta') and hasattr(view.get_serializer().Meta, 'model'): | ||||
|         model = view.get_serializer().Meta.model | ||||
|     if model: | ||||
|         return getattr(model, '_meta').verbose_name | ||||
|     return "" | ||||
|  |  | |||
|  | @ -0,0 +1,35 @@ | |||
| import request from '@/utils/request' | ||||
| 
 | ||||
| // 查询操作日志列表 | ||||
| export function list(query) { | ||||
|   return request({ | ||||
|     url: '/admin/system/operation_log/', | ||||
|     method: 'get', | ||||
|     params: query | ||||
|   }) | ||||
| } | ||||
| 
 | ||||
| // 删除操作日志 | ||||
| export function delOperationLog(operId) { | ||||
|   return request({ | ||||
|     url: '/admin/system/operation_log/' + operId + '/', | ||||
|     method: 'delete' | ||||
|   }) | ||||
| } | ||||
| 
 | ||||
| // 清空操作日志 | ||||
| export function cleanOperationLog() { | ||||
|   return request({ | ||||
|     url: '/admin/system/operation_log/clean/', | ||||
|     method: 'delete' | ||||
|   }) | ||||
| } | ||||
| 
 | ||||
| // 导出操作日志 | ||||
| export function exportOperationLog(query) { | ||||
|   return request({ | ||||
|     url: '/admin/system/operation_log/export/', | ||||
|     method: 'get', | ||||
|     params: query | ||||
|   }) | ||||
| } | ||||
|  | @ -98,6 +98,18 @@ export const constantRoutes = [ | |||
|         meta: { title: '字典数据', icon: '' } | ||||
|       } | ||||
|     ] | ||||
|   },{ | ||||
|     path: '/operlog', | ||||
|     component: Layout, | ||||
|     hidden: false, | ||||
|     children: [ | ||||
|       { | ||||
|         path: 'log', | ||||
|         component: (resolve) => require(['@/views/vadmin/system/operlog'], resolve), | ||||
|         name: 'Data', | ||||
|         meta: { title: '操作日志', icon: '' } | ||||
|       } | ||||
|     ] | ||||
|   } | ||||
| ] | ||||
| 
 | ||||
|  |  | |||
|  | @ -56,16 +56,13 @@ export function resetForm(refName) { | |||
| // 添加日期范围 | ||||
| export function addDateRange(params, dateRange, propName) { | ||||
| 	var search = params; | ||||
| 	search.params = {}; | ||||
| 	if (null != dateRange && '' != dateRange) { | ||||
| 		if (typeof(propName) === "undefined") { | ||||
| 			search.params["beginTime"] = dateRange[0]; | ||||
| 			search.params["endTime"] = dateRange[1]; | ||||
| 		} else { | ||||
| 			search.params["begin" + propName] = dateRange[0]; | ||||
| 			search.params["end" + propName] = dateRange[1]; | ||||
| 		} | ||||
| 	  // create_datetime__range = this.dateRange | ||||
|     var dateTime=new Date(); | ||||
| 
 | ||||
|     search.as = JSON.stringify({create_datetime__range : dateRange}); | ||||
| 	} | ||||
| 	console.log(11,search) | ||||
| 	return search; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,292 @@ | |||
| <template> | ||||
|   <div class="app-container"> | ||||
|     <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px"> | ||||
|       <el-form-item label="系统模块" prop="request_modular"> | ||||
|         <el-input | ||||
|           v-model="queryParams.request_modular" | ||||
|           placeholder="请输入系统模块" | ||||
|           clearable | ||||
|           style="width: 240px;" | ||||
|           size="small" | ||||
|           @keyup.enter.native="handleQuery" | ||||
|         /> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="操作人员" prop="creator_name"> | ||||
|         <el-input | ||||
|           v-model="queryParams.creator_name" | ||||
|           placeholder="请输入操作人员" | ||||
|           clearable | ||||
|           style="width: 240px;" | ||||
|           size="small" | ||||
|           @keyup.enter.native="handleQuery" | ||||
|         /> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="状态" prop="status"> | ||||
|         <el-select | ||||
|           v-model="queryParams.status" | ||||
|           placeholder="操作状态" | ||||
|           clearable | ||||
|           size="small" | ||||
|           style="width: 240px" | ||||
|         > | ||||
|           <el-option | ||||
|             v-for="dict in statusOptions" | ||||
|             :key="dict.dictValue" | ||||
|             :label="dict.dictLabel" | ||||
|             :value="dict.dictValue" | ||||
|           /> | ||||
|         </el-select> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="操作时间"> | ||||
|         <el-date-picker | ||||
|           v-model="dateRange" | ||||
|           size="small" | ||||
|           style="width: 240px" | ||||
|           value-format="yyyy-MM-dd HH:mm:ss" | ||||
|           type="daterange" | ||||
|           range-separator="-" | ||||
|           start-placeholder="开始日期" | ||||
|           end-placeholder="结束日期" | ||||
|           :default-time="['00:00:00', '23:59:59']" | ||||
|         ></el-date-picker> | ||||
|       </el-form-item> | ||||
|       <el-form-item> | ||||
|         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> | ||||
|         <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> | ||||
|       </el-form-item> | ||||
|     </el-form> | ||||
| 
 | ||||
|     <el-row :gutter="10" class="mb8"> | ||||
|       <el-col :span="1.5"> | ||||
|         <el-button | ||||
|           type="danger" | ||||
|           plain | ||||
|           icon="el-icon-delete" | ||||
|           size="mini" | ||||
|           :disabled="multiple" | ||||
|           @click="handleDelete" | ||||
|           v-hasPermi="['monitor:operlog:remove']" | ||||
|         >删除</el-button> | ||||
|       </el-col> | ||||
|       <el-col :span="1.5"> | ||||
|         <el-button | ||||
|           type="danger" | ||||
|           plain | ||||
|           icon="el-icon-delete" | ||||
|           size="mini" | ||||
|           @click="handleClean" | ||||
|           v-hasPermi="['monitor:operlog:remove']" | ||||
|         >清空</el-button> | ||||
|       </el-col> | ||||
|       <el-col :span="1.5"> | ||||
|         <el-button | ||||
|           type="warning" | ||||
|           plain | ||||
|           icon="el-icon-download" | ||||
|           size="mini" | ||||
|           @click="handleExport" | ||||
|           v-hasPermi="['system:config:export']" | ||||
|         >导出</el-button> | ||||
|       </el-col> | ||||
|       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> | ||||
|     </el-row> | ||||
| 
 | ||||
|     <el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange"> | ||||
|       <el-table-column type="selection" width="55" align="center" /> | ||||
|       <el-table-column label="日志编号" align="center" prop="id" /> | ||||
|       <el-table-column label="系统模块" align="center" prop="request_modular" /> | ||||
|       <el-table-column label="请求方式" align="center" prop="request_method" /> | ||||
|       <el-table-column label="操作人员" align="center" prop="creator_name" /> | ||||
|       <el-table-column label="主机" align="center" prop="request_ip" width="130" :show-overflow-tooltip="true" /> | ||||
|       <el-table-column label="操作地点" align="center" prop="request_location" :show-overflow-tooltip="true" /> | ||||
|       <el-table-column label="操作状态" align="center" prop="status" :formatter="statusFormat" /> | ||||
|       <el-table-column label="操作日期" align="center" prop="create_datetime" width="180"> | ||||
|         <template slot-scope="scope"> | ||||
|           <span>{{ parseTime(scope.row.create_datetime) }}</span> | ||||
|         </template> | ||||
|       </el-table-column> | ||||
|       <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> | ||||
|         <template slot-scope="scope"> | ||||
|           <el-button | ||||
|             size="mini" | ||||
|             type="text" | ||||
|             icon="el-icon-view" | ||||
|             @click="handleView(scope.row,scope.index)" | ||||
|             v-hasPermi="['monitor:operlog:query']" | ||||
|           >详细</el-button> | ||||
|         </template> | ||||
|       </el-table-column> | ||||
|     </el-table> | ||||
| 
 | ||||
|     <pagination | ||||
|       v-show="total>0" | ||||
|       :total="total" | ||||
|       :page.sync="queryParams.pageNum" | ||||
|       :limit.sync="queryParams.pageSize" | ||||
|       @pagination="getList" | ||||
|     /> | ||||
| 
 | ||||
|     <!-- 操作日志详细 --> | ||||
|     <el-dialog title="操作日志详细" :visible.sync="open" width="700px" append-to-body> | ||||
|       <el-form ref="form" :model="form" label-width="100px" size="mini"> | ||||
|         <el-row> | ||||
|           <el-col :span="12"> | ||||
|             <el-form-item label="操作模块:">{{ form.request_modular }} / {{ form.request_msg }}</el-form-item> | ||||
|             <el-form-item | ||||
|               label="登录信息:" | ||||
|             >{{ form.creator_name }} / {{ form.request_ip }} / {{ form.request_location }} / {{ form.request_browser }}</el-form-item> | ||||
|           </el-col> | ||||
|           <el-col :span="12"> | ||||
|             <el-form-item label="请求地址:">{{ form.request_path }}</el-form-item> | ||||
|             <el-form-item label="请求方式:">{{ form.request_method }}</el-form-item> | ||||
|           </el-col> | ||||
|           <el-col :span="24"> | ||||
|             <el-form-item label="请求参数:">{{ form.request_body }}</el-form-item> | ||||
|           </el-col> | ||||
|           <el-col :span="24"> | ||||
|             <el-form-item label="返回参数:">{{ form.json_result }}</el-form-item> | ||||
|           </el-col> | ||||
|           <el-col :span="24"> | ||||
|             <el-form-item label="返回状态码:">{{ form.response_code }}</el-form-item> | ||||
|           </el-col> | ||||
|           <el-col :span="12"> | ||||
|             <el-form-item label="操作状态:"> | ||||
|               <div v-if="form.status === true">正常</div> | ||||
|               <div v-else-if="form.status === false">失败</div> | ||||
|             </el-form-item> | ||||
|           </el-col> | ||||
|           <el-col :span="12"> | ||||
|             <el-form-item label="操作时间:">{{ parseTime(form.create_datetime) }}</el-form-item> | ||||
|           </el-col> | ||||
| <!--          <el-col :span="24">--> | ||||
| <!--            <el-form-item label="异常信息:" v-if="form.status === false">{{ form.json_result }}</el-form-item>--> | ||||
| <!--          </el-col>--> | ||||
|         </el-row> | ||||
|       </el-form> | ||||
|       <div slot="footer" class="dialog-footer"> | ||||
|         <el-button @click="open = false">关 闭</el-button> | ||||
|       </div> | ||||
|     </el-dialog> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
|   import {cleanOperationLog, delOperationLog, exportOperationLog, list} from "@/api/vadmin/system/operationlog"; | ||||
| 
 | ||||
|   export default { | ||||
|   name: "Operlog", | ||||
|   data() { | ||||
|     return { | ||||
|       // 遮罩层 | ||||
|       loading: true, | ||||
|       // 选中数组 | ||||
|       ids: [], | ||||
|       // 非多个禁用 | ||||
|       multiple: true, | ||||
|       // 显示搜索条件 | ||||
|       showSearch: true, | ||||
|       // 总条数 | ||||
|       total: 0, | ||||
|       // 表格数据 | ||||
|       list: [], | ||||
|       // 是否显示弹出层 | ||||
|       open: false, | ||||
|       // 类型数据字典 | ||||
|       statusOptions: [{dictLabel: '成功', dictValue: true}, {dictLabel: '失败', dictValue: false}], | ||||
|       // 日期范围 | ||||
|       dateRange: [], | ||||
|       // 表单参数 | ||||
|       form: {}, | ||||
|       // 查询参数 | ||||
|       queryParams: { | ||||
|         pageNum: 1, | ||||
|         pageSize: 10, | ||||
|         request_modular: undefined, | ||||
|         creator_name: undefined, | ||||
|         status: undefined | ||||
|       } | ||||
|     }; | ||||
|   }, | ||||
|   created() { | ||||
|     this.getList(); | ||||
|   }, | ||||
|   methods: { | ||||
|     /** 查询登录日志 */ | ||||
|     getList() { | ||||
|       this.loading = true; | ||||
|       list(this.addDateRange(this.queryParams, this.dateRange)).then(response => { | ||||
|           this.list = response.data.results; | ||||
|           this.total = response.data.count; | ||||
|           this.loading = false; | ||||
|         } | ||||
|       ); | ||||
|     }, | ||||
|     // 操作日志状态字典翻译 | ||||
|     statusFormat(row, column) { | ||||
|       return this.selectDictLabel(this.statusOptions, row.status); | ||||
|     }, | ||||
|     /** 搜索按钮操作 */ | ||||
|     handleQuery() { | ||||
|       this.queryParams.pageNum = 1; | ||||
|       this.getList(); | ||||
|     }, | ||||
|     /** 重置按钮操作 */ | ||||
|     resetQuery() { | ||||
|       this.dateRange = []; | ||||
|       this.resetForm("queryForm"); | ||||
|       this.handleQuery(); | ||||
|     }, | ||||
|     // 多选框选中数据 | ||||
|     handleSelectionChange(selection) { | ||||
|       this.ids = selection.map(item => item.id) | ||||
|       this.multiple = !selection.length | ||||
|     }, | ||||
|     /** 详细按钮操作 */ | ||||
|     handleView(row) { | ||||
|       this.open = true; | ||||
|       this.form = row; | ||||
|     }, | ||||
|     /** 删除按钮操作 */ | ||||
|     handleDelete(row) { | ||||
|       const ids = row.id || this.ids; | ||||
|       this.$confirm('是否确认删除日志编号为"' + ids + '"的数据项?', "警告", { | ||||
|           confirmButtonText: "确定", | ||||
|           cancelButtonText: "取消", | ||||
|           type: "warning" | ||||
|         }).then(function() { | ||||
|           return delOperationLog(ids); | ||||
|         }).then(() => { | ||||
|           this.getList(); | ||||
|           this.msgSuccess("删除成功"); | ||||
|         }) | ||||
|     }, | ||||
|     /** 清空按钮操作 */ | ||||
|     handleClean() { | ||||
|         this.$confirm('是否确认清空所有操作日志数据项?', "警告", { | ||||
|           confirmButtonText: "确定", | ||||
|           cancelButtonText: "取消", | ||||
|           type: "warning" | ||||
|         }).then(function() { | ||||
|           return cleanOperationLog(); | ||||
|         }).then(() => { | ||||
|           this.getList(); | ||||
|           this.msgSuccess("清空成功"); | ||||
|         }) | ||||
|     }, | ||||
|     /** 导出按钮操作 */ | ||||
|     handleExport() { | ||||
|       const queryParams = this.queryParams; | ||||
|       this.$confirm('是否确认导出所有操作日志数据项?', "警告", { | ||||
|           confirmButtonText: "确定", | ||||
|           cancelButtonText: "取消", | ||||
|           type: "warning" | ||||
|         }).then(function() { | ||||
|           return exportOperationLog(queryParams); | ||||
|         }).then(response => { | ||||
|           this.download(response.data.file_url,response.data.name); | ||||
|         }) | ||||
|     } | ||||
|   } | ||||
| }; | ||||
| </script> | ||||
| 
 | ||||
		Loading…
	
		Reference in New Issue
	
	 李强
						李强