mirror of
				https://github.com/continew-org/continew-admin-ui.git
				synced 2025-10-31 10:57:10 +08:00 
			
		
		
		
	refactor: 系统管理/系统日志 => 系统监控/系统日志
This commit is contained in:
		| @@ -1 +1,2 @@ | ||||
| export * from './online' | ||||
| export * from './log' | ||||
|   | ||||
							
								
								
									
										24
									
								
								src/apis/monitor/log.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/apis/monitor/log.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| import http from '@/utils/http' | ||||
| import type * as Monitor from './type' | ||||
|  | ||||
| const BASE_URL = '/system/log' | ||||
|  | ||||
| /** @desc 查询日志列表 */ | ||||
| export function listLog(query: Monitor.LogPageQuery) { | ||||
|   return http.get<PageRes<Monitor.LogResp[]>>(`${BASE_URL}`, query) | ||||
| } | ||||
|  | ||||
| /** @desc 查询日志详情 */ | ||||
| export function getLog(id: string) { | ||||
|   return http.get<Monitor.LogDetailResp>(`${BASE_URL}/${id}`) | ||||
| } | ||||
|  | ||||
| /** @desc 导出登录日志 */ | ||||
| export function exportLoginLog(query: Monitor.LogQuery) { | ||||
|   return http.download<any>(`${BASE_URL}/export/login`, query) | ||||
| } | ||||
|  | ||||
| /** @desc 导出操作日志 */ | ||||
| export function exportOperationLog(query: Monitor.LogQuery) { | ||||
|   return http.download<any>(`${BASE_URL}/export/operation`, query) | ||||
| } | ||||
| @@ -13,8 +13,43 @@ export interface OnlineUserResp { | ||||
|   createUserString: string | ||||
|   createTime: string | ||||
| } | ||||
|  | ||||
| export interface OnlineUserQuery extends PageQuery { | ||||
|   nickname?: string | ||||
|   loginTime?: string | ||||
| } | ||||
|  | ||||
| /** 系统日志类型 */ | ||||
| export interface LogResp { | ||||
|   id: string | ||||
|   description: string | ||||
|   module: string | ||||
|   timeTaken: number | ||||
|   ip: string | ||||
|   address: string | ||||
|   browser: string | ||||
|   os: string | ||||
|   status: number | ||||
|   errorMsg: string | ||||
|   createUserString: string | ||||
|   createTime: string | ||||
| } | ||||
| export interface LogDetailResp extends LogResp { | ||||
|   traceId: string | ||||
|   requestUrl: string | ||||
|   requestMethod: string | ||||
|   requestHeaders: string | ||||
|   requestBody: string | ||||
|   statusCode: number | ||||
|   responseHeaders: string | ||||
|   responseBody: string | ||||
| } | ||||
| export interface LogQuery{ | ||||
|   description?: string | ||||
|   module?: string | ||||
|   ip?: string | ||||
|   createUserString?: string | ||||
|   createTime?: string | ||||
|   status?: number | ||||
|   sort: Array<string> | ||||
| } | ||||
| export interface LogPageQuery extends PageQuery, LogQuery {} | ||||
|   | ||||
| @@ -2,7 +2,7 @@ export * from './user' | ||||
| export * from './role' | ||||
| export * from './menu' | ||||
| export * from './dept' | ||||
| export * from './log' | ||||
| export * from '../monitor/log' | ||||
| export * from './dict' | ||||
| export * from './file' | ||||
| export * from './storage' | ||||
|   | ||||
| @@ -1,22 +0,0 @@ | ||||
| import http from '@/utils/http' | ||||
| import type * as System from './type' | ||||
|  | ||||
| const BASE_URL = '/system/log' | ||||
|  | ||||
| /** @desc 查询日志列表 */ | ||||
| export function listLog(query: System.PageLogQuery) { | ||||
|   return http.get<PageRes<System.LogResp[]>>(`${BASE_URL}`, query) | ||||
| } | ||||
|  | ||||
| /** @desc 查询日志详情 */ | ||||
| export function getLog(id: string) { | ||||
|   return http.get<System.LogDetailResp>(`${BASE_URL}/${id}`) | ||||
| } | ||||
| /** @desc 导出日志列表 */ | ||||
| export function exportLog(query: System.LogQuery) { | ||||
|   return http.download<any>(`${BASE_URL}/export/login`, query) | ||||
| } | ||||
| /**@desc 导出操作日志 */ | ||||
| export function exportOperateLog(query: System.LogQuery) { | ||||
|   return http.download<any>(`${BASE_URL}/export/operation`, query) | ||||
| } | ||||
| @@ -119,43 +119,6 @@ export interface DeptQuery { | ||||
|   sort: Array<string> | ||||
| } | ||||
|  | ||||
| /** 系统日志类型 */ | ||||
| export interface LogResp { | ||||
|   id: string | ||||
|   description: string | ||||
|   module: string | ||||
|   timeTaken: number | ||||
|   ip: string | ||||
|   address: string | ||||
|   browser: string | ||||
|   os: string | ||||
|   status: number | ||||
|   errorMsg: string | ||||
|   createUserString: string | ||||
|   createTime: string | ||||
| } | ||||
| export interface LogDetailResp extends LogResp { | ||||
|   traceId: string | ||||
|   requestUrl: string | ||||
|   requestMethod: string | ||||
|   requestHeaders: string | ||||
|   requestBody: string | ||||
|   statusCode: number | ||||
|   responseHeaders: string | ||||
|   responseBody: string | ||||
| } | ||||
| // 系统日志分页查询条件 | ||||
| export interface PageLogQuery extends PageQuery,LogQuery{} | ||||
| // 系统日志查询条件 | ||||
| export interface LogQuery{ | ||||
|   description?: string | ||||
|   module?: string | ||||
|   ip?: string | ||||
|   createUserString?: string | ||||
|   createTime?: string | ||||
|   status?: number | ||||
| } | ||||
|  | ||||
| /** 系统字典类型 */ | ||||
| export interface DictResp { | ||||
|   id: string | ||||
|   | ||||
| @@ -1,29 +1,35 @@ | ||||
| <template> | ||||
|   <div class="json_prettt_container"> | ||||
|   <div class="json_pretty_container"> | ||||
|     <vue-json-pretty | ||||
|               :path="'res'" | ||||
|               :data="JSONObject" | ||||
|               :show-length="true" | ||||
|             /> | ||||
|     <icon-copy class="copy_icon" @click="onCopy(JSONObject)"/> | ||||
|       :path="'res'" | ||||
|       :data="JSONObject" | ||||
|       :show-length="true" | ||||
|     /> | ||||
|     <icon-copy class="copy_icon" @click="onCopy(JSONObject)" /> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import VueJsonPretty from 'vue-json-pretty' | ||||
| import 'vue-json-pretty/lib/styles.css' | ||||
| import {copyText} from '@/utils' | ||||
| import { copyText } from '@/utils' | ||||
|  | ||||
| defineOptions({ name: 'JsonPretty', inheritAttrs: false }) | ||||
|  | ||||
| const props = defineProps<{ | ||||
|   josn: string | ||||
|   json: string | ||||
| }>() | ||||
| const JSONObject = computed(()=>JSON.parse(props?.josn)) | ||||
| const onCopy =(data:object)=>{ | ||||
|  | ||||
| const JSONObject = computed(() => JSON.parse(props?.json)) | ||||
|  | ||||
| // 拷贝 | ||||
| const onCopy = (data: object) => { | ||||
|   copyText(JSON.stringify(data)) | ||||
|   console.log('copyObject',data) | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .json_prettt_container{ | ||||
| .json_pretty_container{ | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
|   overflow: auto; | ||||
|   | ||||
| @@ -6,8 +6,8 @@ | ||||
|     :loading="loading" | ||||
|     :scroll="{ x: '100%', y: '100%', minWidth: 1000 }" | ||||
|     :pagination="pagination" | ||||
|     @filterChange="filterChange" | ||||
|     :disabledTools="['setting']" | ||||
|     @filterChange="filterChange" | ||||
|     @refresh="search" | ||||
|   > | ||||
|     <template #custom-left> | ||||
| @@ -22,7 +22,7 @@ | ||||
|     </template> | ||||
|     <template #custom-right> | ||||
|       <a-tooltip content="导出"> | ||||
|         <a-button @click="onExportFile"> | ||||
|         <a-button @click="onExport"> | ||||
|           <template #icon> | ||||
|             <icon-download /> | ||||
|           </template> | ||||
| @@ -45,22 +45,13 @@ | ||||
| </template> | ||||
| 
 | ||||
| <script setup lang="ts"> | ||||
| import { listLog,exportLog } from '@/apis' | ||||
| import { exportLoginLog, listLog } from '@/apis' | ||||
| import type { TableInstance } from '@arco-design/web-vue' | ||||
| import DateRangePicker from '@/components/DateRangePicker/index.vue' | ||||
| import { useTable } from '@/hooks' | ||||
| import {useDownload} from '@/hooks' | ||||
| import { useTable, useDownload } from '@/hooks' | ||||
| 
 | ||||
| defineOptions({ name: 'LoginLog' }) | ||||
| const filterChange = (values,record)=>{ | ||||
|   try { | ||||
|     const slotName = columns[values.split('_').pop()].slotName as string | ||||
|     const value = record.join(',') | ||||
|     queryForm[slotName] = value | ||||
|     search() | ||||
|   } catch (error) { | ||||
|     search() | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| const columns: TableInstance['columns'] = [ | ||||
|   { | ||||
|     title: '序号', | ||||
| @@ -95,10 +86,7 @@ const columns: TableInstance['columns'] = [ | ||||
|   { title: '浏览器', dataIndex: 'browser', ellipsis: true, tooltip: true }, | ||||
|   { title: '终端系统', dataIndex: 'os', ellipsis: true, tooltip: true } | ||||
| ] | ||||
| //导出登录日志 | ||||
| const onExportFile = ()=>{ | ||||
|   useDownload(()=>exportLog(queryForm)) | ||||
| } | ||||
| 
 | ||||
| const queryForm = reactive({ | ||||
|   module: '登录', | ||||
|   ip: undefined, | ||||
| @@ -123,6 +111,22 @@ const reset = () => { | ||||
|   queryForm.status = undefined | ||||
|   search() | ||||
| } | ||||
| 
 | ||||
| // 导出 | ||||
| const onExport = () => { | ||||
|   useDownload(() => exportLoginLog(queryForm)) | ||||
| } | ||||
| 
 | ||||
| // 过滤查询 | ||||
| const filterChange = (dataIndex, filteredValues) => { | ||||
|   try { | ||||
|     const slotName = columns[dataIndex.split('_').pop()].slotName as string | ||||
|     queryForm[slotName] = filteredValues.join(',') | ||||
|     search() | ||||
|   } catch (error) { | ||||
|     search() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped></style> | ||||
| @@ -7,8 +7,8 @@ | ||||
|     :scroll="{ x: '100%', y: '100%', minWidth: 1000 }" | ||||
|     :pagination="pagination" | ||||
|     column-resizable | ||||
|     @filterChange="filterChange" | ||||
|     :disabledTools="['setting']" | ||||
|     @filterChange="filterChange" | ||||
|     @refresh="search" | ||||
|   > | ||||
|     <template #custom-left> | ||||
| @@ -22,8 +22,8 @@ | ||||
|       <a-button @click="reset">重置</a-button> | ||||
|     </template> | ||||
|     <template #custom-right> | ||||
|       <a-tooltip content="导出" @click="onExportFile"> | ||||
|         <a-button> | ||||
|       <a-tooltip content="导出"> | ||||
|         <a-button @click="onExport"> | ||||
|           <template #icon> | ||||
|             <icon-download /> | ||||
|           </template> | ||||
| @@ -56,23 +56,14 @@ | ||||
| </template> | ||||
| 
 | ||||
| <script setup lang="ts"> | ||||
| import { listLog, type LogResp,exportOperateLog } from '@/apis' | ||||
| import { listLog, exportOperationLog, type LogResp } from '@/apis' | ||||
| import type { TableInstance } from '@arco-design/web-vue' | ||||
| import DateRangePicker from '@/components/DateRangePicker/index.vue' | ||||
| import OperationLogDetailDrawer from './OperationLogDetailDrawer.vue' | ||||
| import { useDownload, useTable } from '@/hooks' | ||||
| import { useTable, useDownload } from '@/hooks' | ||||
| 
 | ||||
| defineOptions({ name: 'OperationLog' }) | ||||
| const filterChange = (values,record)=>{ | ||||
|   try { | ||||
|     const slotName = columns[values.split('_').pop()].slotName as string | ||||
|     const value = record.join(',') | ||||
|     queryForm[slotName] = value | ||||
|     search() | ||||
|   } catch (error) { | ||||
|     search() | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| const columns: TableInstance['columns'] = [ | ||||
|   { | ||||
|     title: '序号', | ||||
| @@ -109,10 +100,7 @@ const columns: TableInstance['columns'] = [ | ||||
|   { title: '浏览器', dataIndex: 'browser', ellipsis: true, tooltip: true }, | ||||
|   { title: '终端系统', dataIndex: 'os', ellipsis: true, tooltip: true } | ||||
| ] | ||||
| //导出操作日志 | ||||
| const onExportFile = ()=>{ | ||||
|   useDownload(()=>exportOperateLog(queryForm)) | ||||
| } | ||||
| 
 | ||||
| const queryForm = reactive({ | ||||
|   description: undefined, | ||||
|   ip: undefined, | ||||
| @@ -139,6 +127,22 @@ const reset = () => { | ||||
|   search() | ||||
| } | ||||
| 
 | ||||
| // 导出 | ||||
| const onExport = () => { | ||||
|   useDownload(() => exportOperationLog(queryForm)) | ||||
| } | ||||
| 
 | ||||
| // 过滤查询 | ||||
| const filterChange = (dataIndex, filteredValues) => { | ||||
|   try { | ||||
|     const slotName = columns[dataIndex.split('_').pop()].slotName as string | ||||
|     queryForm[slotName] = filteredValues.join(',') | ||||
|     search() | ||||
|   } catch (error) { | ||||
|     search() | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| const OperationLogDetailDrawerRef = ref<InstanceType<typeof OperationLogDetailDrawer>>() | ||||
| // 查询详情 | ||||
| const openDetail = (item: LogResp) => { | ||||
							
								
								
									
										106
									
								
								src/views/monitor/log/OperationLogDetailDrawer.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								src/views/monitor/log/OperationLogDetailDrawer.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,106 @@ | ||||
| <template> | ||||
|   <a-drawer v-model:visible="visible" title="日志详情" :width="720" :footer="false"> | ||||
|     <a-descriptions title="基本信息" :column="2" size="large" class="general-description"> | ||||
|       <a-descriptions-item label="日志 ID">{{ dataDetail?.id }}</a-descriptions-item> | ||||
|       <a-descriptions-item label="Trace ID" >{{ dataDetail?.traceId }}<TextCopy :value="dataDetail?.traceId" /></a-descriptions-item> | ||||
|       <a-descriptions-item label="操作人">{{ dataDetail?.createUserString }}</a-descriptions-item> | ||||
|       <a-descriptions-item label="操作时间">{{ dataDetail?.createTime }}</a-descriptions-item> | ||||
|       <a-descriptions-item label="操作内容">{{ dataDetail?.description }}</a-descriptions-item> | ||||
|       <a-descriptions-item label="所属模块">{{ dataDetail?.module }}</a-descriptions-item> | ||||
|       <a-descriptions-item label="操作 IP">{{ dataDetail?.ip }}</a-descriptions-item> | ||||
|       <a-descriptions-item label="操作地点">{{ dataDetail?.address }}</a-descriptions-item> | ||||
|       <a-descriptions-item label="浏览器">{{ dataDetail?.browser }}</a-descriptions-item> | ||||
|       <a-descriptions-item label="终端系统">{{ dataDetail?.os }}</a-descriptions-item> | ||||
|       <a-descriptions-item label="状态"> | ||||
|         <a-tag v-if="dataDetail?.status === 1" color="green">成功</a-tag> | ||||
|         <a-tag v-else color="red">失败</a-tag> | ||||
|       </a-descriptions-item> | ||||
|       <a-descriptions-item label="耗时"> | ||||
|         <a-tag v-if="dataDetail?.timeTaken > 500" color="red"> | ||||
|           {{ dataDetail?.timeTaken }}ms | ||||
|         </a-tag> | ||||
|         <a-tag v-else-if="dataDetail?.timeTaken > 200" color="orange"> | ||||
|           {{ dataDetail?.timeTaken }}ms | ||||
|         </a-tag> | ||||
|         <a-tag v-else color="green">{{ dataDetail?.timeTaken }} ms</a-tag> | ||||
|       </a-descriptions-item> | ||||
|       <a-descriptions-item label="请求 URI" :span="2"> | ||||
|         {{ dataDetail?.requestUrl }}<TextCopy :value="dataDetail?.requestUrl" /> | ||||
|       </a-descriptions-item> | ||||
|     </a-descriptions> | ||||
|     <a-descriptions | ||||
|       title="响应信息" | ||||
|       :column="2" | ||||
|       size="large" | ||||
|       class="general-description http" | ||||
|       style="margin-top: 20px; position: relative" | ||||
|     > | ||||
|       <a-descriptions-item :span="2"> | ||||
|         <a-tabs type="card"> | ||||
|           <a-tab-pane key="1" title="响应头"> | ||||
|             <JsonPretty v-if="dataDetail?.responseHeaders" :json="dataDetail?.responseHeaders" /> | ||||
|             <span v-else>无</span> | ||||
|           </a-tab-pane> | ||||
|           <a-tab-pane key="2" title="响应体"> | ||||
|             <JsonPretty v-if="dataDetail?.responseBody" :json="dataDetail?.responseBody" /> | ||||
|             <span v-else>无</span> | ||||
|           </a-tab-pane> | ||||
|         </a-tabs> | ||||
|       </a-descriptions-item> | ||||
|     </a-descriptions> | ||||
|     <a-descriptions | ||||
|       title="请求信息" | ||||
|       :column="2" | ||||
|       size="large" | ||||
|       class="general-description http" | ||||
|       style="margin-top: 20px; position: relative" | ||||
|     > | ||||
|       <a-descriptions-item :span="2"> | ||||
|         <a-tabs type="card"> | ||||
|           <a-tab-pane key="1" title="请求头"> | ||||
|             <JsonPretty v-if="dataDetail?.requestHeaders" :json="dataDetail?.requestHeaders" /> | ||||
|             <span v-else>无</span> | ||||
|           </a-tab-pane> | ||||
|           <a-tab-pane key="2" title="请求体"> | ||||
|             <JsonPretty v-if="dataDetail?.requestBody" :json="dataDetail?.requestBody" /> | ||||
|             <span v-else>无</span> | ||||
|           </a-tab-pane> | ||||
|         </a-tabs> | ||||
|       </a-descriptions-item> | ||||
|     </a-descriptions> | ||||
|   </a-drawer> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { getLog, type LogDetailResp } from '@/apis' | ||||
|  | ||||
| const dataId = ref('') | ||||
| const dataDetail = ref<LogDetailResp>() | ||||
|  | ||||
| // 查询详情 | ||||
| const getDataDetail = async () => { | ||||
|   const res = await getLog(dataId.value) | ||||
|   dataDetail.value = res.data | ||||
| } | ||||
|  | ||||
| const visible = ref(false) | ||||
| // 打开详情 | ||||
| const open = async (id: string) => { | ||||
|   dataId.value = id | ||||
|   await getDataDetail() | ||||
|   visible.value = true | ||||
| } | ||||
|  | ||||
| defineExpose({ open }) | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .http :deep(.arco-descriptions-item-label-block) { | ||||
|   padding-right: 0; | ||||
| } | ||||
|  | ||||
| :deep(.arco-tabs-content) { | ||||
|   padding-top: 5px; | ||||
|   padding-left: 15px; | ||||
| } | ||||
| </style> | ||||
| @@ -1,12 +1,12 @@ | ||||
| <template> | ||||
|   <div class="gi_page"> | ||||
|     <a-card title="系统日志" class="general-card"> | ||||
|       <a-tabs  type="card-gutter" size="large" :active-key="activeKey" @change="change"> | ||||
|         <a-tab-pane key="1" title="登录日志"/> | ||||
|         <a-tab-pane key="2" title="操作日志"/> | ||||
|       <a-tabs type="card-gutter" size="large" :active-key="activeKey" @change="change"> | ||||
|         <a-tab-pane key="1" title="登录日志" /> | ||||
|         <a-tab-pane key="2" title="操作日志" /> | ||||
|       </a-tabs> | ||||
|       <keep-alive> | ||||
|           <component :is="PaneMap[activeKey]"></component> | ||||
|           <component :is="PaneMap[activeKey]" /> | ||||
|       </keep-alive> | ||||
|     </a-card> | ||||
|   </div> | ||||
| @@ -15,12 +15,15 @@ | ||||
| <script setup lang="ts"> | ||||
| import LoginLog from './LoginLog.vue' | ||||
| import OperationLog from './OperationLog.vue' | ||||
| 
 | ||||
| const route = useRoute() | ||||
| const router = useRouter() | ||||
| const PaneMap:Record<string,Component> = { | ||||
| 
 | ||||
| const PaneMap: Record<string, Component> = { | ||||
|   '1': LoginLog, | ||||
|   '2': OperationLog | ||||
| } | ||||
| 
 | ||||
| const activeKey = ref('1') | ||||
| watch( | ||||
|   () => route.query, | ||||
| @@ -31,6 +34,7 @@ watch( | ||||
|   }, | ||||
|   { immediate: true } | ||||
| ) | ||||
| 
 | ||||
| const change = (key: string | number) => { | ||||
|   activeKey.value = key as string | ||||
|   router.replace({ path: route.path, query: { tabKey: key } }) | ||||
| @@ -1,105 +0,0 @@ | ||||
| <template> | ||||
|   <a-drawer v-model:visible="visible" title="日志详情" :width="720" :footer="false"> | ||||
|     <a-descriptions title="基本信息" :column="2" size="large" class="general-description"> | ||||
|       <a-descriptions-item label="日志 ID">{{ operationLog?.id }}</a-descriptions-item> | ||||
|       <a-descriptions-item label="Trace ID" >{{ operationLog?.traceId }}<TextCopy :value="operationLog?.traceId"/></a-descriptions-item> | ||||
|       <a-descriptions-item label="操作人">{{ operationLog?.createUserString }}</a-descriptions-item> | ||||
|       <a-descriptions-item label="操作时间">{{ operationLog?.createTime }}</a-descriptions-item> | ||||
|       <a-descriptions-item label="操作内容">{{ operationLog?.description }}</a-descriptions-item> | ||||
|       <a-descriptions-item label="所属模块">{{ operationLog?.module }}</a-descriptions-item> | ||||
|       <a-descriptions-item label="操作 IP">{{ operationLog?.ip }}</a-descriptions-item> | ||||
|       <a-descriptions-item label="操作地点">{{ operationLog?.address }}</a-descriptions-item> | ||||
|       <a-descriptions-item label="浏览器">{{ operationLog?.browser }}</a-descriptions-item> | ||||
|       <a-descriptions-item label="终端系统">{{ operationLog?.os }}</a-descriptions-item> | ||||
|       <a-descriptions-item label="状态"> | ||||
|         <a-tag v-if="operationLog?.status === 1" color="green">成功</a-tag> | ||||
|         <a-tag v-else color="red">失败</a-tag> | ||||
|       </a-descriptions-item> | ||||
|       <a-descriptions-item label="耗时"> | ||||
|         <a-tag v-if="operationLog?.timeTaken > 500" color="red"> | ||||
|           {{ operationLog?.timeTaken }}ms | ||||
|         </a-tag> | ||||
|         <a-tag v-else-if="operationLog?.timeTaken > 200" color="orange"> | ||||
|           {{ operationLog?.timeTaken }}ms | ||||
|         </a-tag> | ||||
|         <a-tag v-else color="green">{{ operationLog?.timeTaken }} ms</a-tag> | ||||
|       </a-descriptions-item> | ||||
|       <a-descriptions-item label="请求 URI" :span="2"> | ||||
|         {{ operationLog?.requestUrl }}<TextCopy :value="operationLog?.requestUrl"/> | ||||
|       </a-descriptions-item> | ||||
|     </a-descriptions> | ||||
|     <a-descriptions | ||||
|       title="响应信息" | ||||
|       :column="2" | ||||
|       size="large" | ||||
|       class="general-description http" | ||||
|       style="margin-top: 20px; position: relative" | ||||
|     > | ||||
|       <a-descriptions-item :span="2"> | ||||
|         <a-tabs type="card"> | ||||
|           <a-tab-pane key="1" title="响应头"> | ||||
|             <JsonPretty v-if="operationLog?.responseHeaders" :josn="operationLog?.responseHeaders"/> | ||||
|             <span v-else>无</span> | ||||
|           </a-tab-pane> | ||||
|           <a-tab-pane key="2" title="响应体"> | ||||
|             <JsonPretty v-if="operationLog?.responseBody" :josn="operationLog?.responseBody"/> | ||||
|             <span v-else>无</span> | ||||
|           </a-tab-pane> | ||||
|         </a-tabs> | ||||
|       </a-descriptions-item> | ||||
|     </a-descriptions> | ||||
|     <a-descriptions | ||||
|       title="请求信息" | ||||
|       :column="2" | ||||
|       size="large" | ||||
|       class="general-description http" | ||||
|       style="margin-top: 20px; position: relative" | ||||
|     > | ||||
|       <a-descriptions-item :span="2"> | ||||
|         <a-tabs type="card"> | ||||
|           <a-tab-pane key="1" title="请求头"> | ||||
|             <JsonPretty v-if="operationLog?.requestHeaders" :josn="operationLog?.requestHeaders"/> | ||||
|             <span v-else>无</span> | ||||
|           </a-tab-pane> | ||||
|           <a-tab-pane key="2" title="请求体"> | ||||
|             <JsonPretty v-if="operationLog?.requestBody" :josn="operationLog?.requestBody"/> | ||||
|             <span v-else>无</span> | ||||
|           </a-tab-pane> | ||||
|         </a-tabs> | ||||
|       </a-descriptions-item> | ||||
|     </a-descriptions> | ||||
|   </a-drawer> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { getLog, type LogDetailResp } from '@/apis' | ||||
| import JsonPretty from '@/components/JsonPretty/index.vue' | ||||
| const logId = ref('') | ||||
| const operationLog = ref<LogDetailResp | null>() | ||||
| // 查询详情 | ||||
| const getOperationLogDetail = async () => { | ||||
|   const res = await getLog(logId.value) | ||||
|   operationLog.value = res.data | ||||
| } | ||||
|  | ||||
| const visible = ref(false) | ||||
| // 打开详情 | ||||
| const open = async (id: string) => { | ||||
|   logId.value = id | ||||
|   await getOperationLogDetail() | ||||
|   visible.value = true | ||||
| } | ||||
|  | ||||
| defineExpose({ open }) | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .http :deep(.arco-descriptions-item-label-block) { | ||||
|   padding-right: 0; | ||||
| } | ||||
|  | ||||
| :deep(.arco-tabs-content) { | ||||
|   padding-top: 5px; | ||||
|   padding-left: 15px; | ||||
| } | ||||
| </style> | ||||
		Reference in New Issue
	
	Block a user