1、服务器资源监控代码增加
2、登录日志样式修改
3、移除部分无用assets图片
对比新文件 |
| | |
| | | import request from '@/config/axios' |
| | | |
| | | // 磁盘监控日志 VO |
| | | export interface MonitorDiskVO { |
| | | id: number // 访问ID |
| | | hostName: string // 主机名称 |
| | | hostIp: string // 服务器ip |
| | | disk: string // 盘符 |
| | | diskName: string // 磁盘名 |
| | | spaceTotal: number // 总空间 |
| | | spaceUsed: number // 已用空间 |
| | | spaceUsable: number // 可用空间 |
| | | spaceRatio: number // 空间使用比例 |
| | | } |
| | | |
| | | // 磁盘监控日志 API |
| | | export const MonitorDiskApi = { |
| | | // 查询磁盘监控日志分页 |
| | | getMonitorDiskPage: async (params: any) => { |
| | | return await request.get({ url: `/infra/monitor-disk/page`, params }) |
| | | }, |
| | | |
| | | // 查询磁盘监控日志列表 |
| | | getMonitorDiskList: async (params: any) => { |
| | | return await request.get({ url: `/infra/monitor-disk/getMonitorDiskList`, params }) |
| | | }, |
| | | |
| | | // 查询磁盘监控日志信息 |
| | | getMonitorDiskInfo: async (params: any) => { |
| | | return await request.get({ url: `/infra/monitor-disk/getMonitorDiskInfo`, params }) |
| | | }, |
| | | |
| | | // 查询磁盘监控日志详情 |
| | | getMonitorDisk: async (id: number) => { |
| | | return await request.get({ url: `/infra/monitor-disk/get?id=` + id }) |
| | | }, |
| | | |
| | | // 新增磁盘监控日志 |
| | | createMonitorDisk: async (data: MonitorDiskVO) => { |
| | | return await request.post({ url: `/infra/monitor-disk/create`, data }) |
| | | }, |
| | | |
| | | // 修改磁盘监控日志 |
| | | updateMonitorDisk: async (data: MonitorDiskVO) => { |
| | | return await request.put({ url: `/infra/monitor-disk/update`, data }) |
| | | }, |
| | | |
| | | // 删除磁盘监控日志 |
| | | deleteMonitorDisk: async (id: number) => { |
| | | return await request.delete({ url: `/infra/monitor-disk/delete?id=` + id }) |
| | | }, |
| | | |
| | | // 导出磁盘监控日志 Excel |
| | | exportMonitorDisk: async (params) => { |
| | | return await request.download({ url: `/infra/monitor-disk/export-excel`, params }) |
| | | }, |
| | | } |
对比新文件 |
| | |
| | | import request from '@/config/axios' |
| | | |
| | | // 内存监控日志 VO |
| | | export interface MonitorMemVO { |
| | | id: number // 访问ID |
| | | hostName: string // 主机名称 |
| | | hostIp: string // 服务器ip |
| | | serverName: string // 服务名 |
| | | physicalTotal: number // 总物理内存 |
| | | physicalUsed: number // 已用物理内存 |
| | | physicalFree: number // 剩余物理内存 |
| | | physicalUsage: number // 物理内存使用率 |
| | | runtimeTotal: number // jvm运行总内存 |
| | | runtimeMax: number // jvm最大内存 |
| | | runtimeUsed: number // jvm已用内存 |
| | | runtimeFree: number // jvm空闲内存 |
| | | runtimeUsage: number // jvm内存使用率 |
| | | } |
| | | |
| | | // 内存监控日志 API |
| | | export const MonitorMemApi = { |
| | | // 查询内存监控日志分页 |
| | | getMonitorMemPage: async (params: any) => { |
| | | return await request.get({ url: `/infra/monitor-mem/page`, params }) |
| | | }, |
| | | |
| | | // 查询统计数据列表 |
| | | getMonitorMemList: async (params: any) => { |
| | | return await request.get({ url: `/infra/monitor-mem/getMonitorMemList`, params }) |
| | | }, |
| | | |
| | | // 查询内存监控日志详情 |
| | | getMonitorMem: async (id: number) => { |
| | | return await request.get({ url: `/infra/monitor-mem/get?id=` + id }) |
| | | }, |
| | | |
| | | // 新增内存监控日志 |
| | | createMonitorMem: async (data: MonitorMemVO) => { |
| | | return await request.post({ url: `/infra/monitor-mem/create`, data }) |
| | | }, |
| | | |
| | | // 修改内存监控日志 |
| | | updateMonitorMem: async (data: MonitorMemVO) => { |
| | | return await request.put({ url: `/infra/monitor-mem/update`, data }) |
| | | }, |
| | | |
| | | // 删除内存监控日志 |
| | | deleteMonitorMem: async (id: number) => { |
| | | return await request.delete({ url: `/infra/monitor-mem/delete?id=` + id }) |
| | | }, |
| | | |
| | | // 导出内存监控日志 Excel |
| | | exportMonitorMem: async (params) => { |
| | | return await request.download({ url: `/infra/monitor-mem/export-excel`, params }) |
| | | }, |
| | | } |
对比新文件 |
| | |
| | | <template> |
| | | <svg :width="size" :height="size" viewBox="0 0 100 100"> |
| | | <!-- 背景圆 --> |
| | | <circle cx="50" cy="50" r="50" fill="#eee"/> |
| | | <!-- 使用率扇形 --> |
| | | <path :d="arcPath" fill="#1C134B"/> |
| | | </svg> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed } from 'vue'; |
| | | |
| | | const props = defineProps({ |
| | | used: { type: Number, required: true }, |
| | | total: { type: Number, required: true }, |
| | | size: { type: Number, default: 150 } |
| | | }); |
| | | |
| | | const percentage = computed(() => { |
| | | if (props.total === 0) return 0; |
| | | return (props.used / props.total) * 100; |
| | | }); |
| | | |
| | | const arcPath = computed(() => { |
| | | if (percentage.value >= 100) return ''; |
| | | |
| | | const angle = (percentage.value * 360) / 100; |
| | | const radians = (angle - 90) * Math.PI / 180; |
| | | const x = 50 + 50 * Math.cos(radians); |
| | | const y = 50 + 50 * Math.sin(radians); |
| | | const largeArc = angle > 180 ? 1 : 0; |
| | | |
| | | return `M 50 50 L 50 0 A 50 50 0 ${largeArc} 1 ${x} ${y} L 50 50 Z`; |
| | | }); |
| | | </script> |
对比新文件 |
| | |
| | | import { store } from '@/store' |
| | | import { defineStore } from 'pinia' |
| | | import { KeFuConversationApi, KeFuConversationRespVO } from '@/api/mall/promotion/kefu/conversation' |
| | | import { KeFuMessageRespVO } from '@/api/mall/promotion/kefu/message' |
| | | import { isEmpty } from '@/utils/is' |
| | | |
| | | interface MallKefuInfoVO { |
| | | conversationList: KeFuConversationRespVO[] // 会话列表 |
| | | conversationMessageList: Map<number, KeFuMessageRespVO[]> // 会话消息 |
| | | } |
| | | |
| | | export const useMallKefuStore = defineStore('mall-kefu', { |
| | | state: (): MallKefuInfoVO => ({ |
| | | conversationList: [], |
| | | conversationMessageList: new Map<number, KeFuMessageRespVO[]>() // key 会话,value 会话消息列表 |
| | | }), |
| | | getters: { |
| | | getConversationList(): KeFuConversationRespVO[] { |
| | | return this.conversationList |
| | | }, |
| | | getConversationMessageList(): (conversationId: number) => KeFuMessageRespVO[] | undefined { |
| | | return (conversationId: number) => this.conversationMessageList.get(conversationId) |
| | | } |
| | | }, |
| | | actions: { |
| | | // ======================= 会话消息相关 ======================= |
| | | /** 缓存历史消息 */ |
| | | saveMessageList(conversationId: number, messageList: KeFuMessageRespVO[]) { |
| | | this.conversationMessageList.set(conversationId, messageList) |
| | | }, |
| | | |
| | | // ======================= 会话相关 ======================= |
| | | /** 加载会话缓存列表 */ |
| | | async setConversationList() { |
| | | this.conversationList = await KeFuConversationApi.getConversationList() |
| | | this.conversationSort() |
| | | }, |
| | | /** 更新会话缓存已读 */ |
| | | async updateConversationStatus(conversationId: number) { |
| | | if (isEmpty(this.conversationList)) { |
| | | return |
| | | } |
| | | const conversation = this.conversationList.find((item) => item.id === conversationId) |
| | | conversation && (conversation.adminUnreadMessageCount = 0) |
| | | }, |
| | | /** 更新会话缓存 */ |
| | | async updateConversation(conversationId: number) { |
| | | if (isEmpty(this.conversationList)) { |
| | | return |
| | | } |
| | | |
| | | const conversation = await KeFuConversationApi.getConversation(conversationId) |
| | | this.deleteConversation(conversationId) |
| | | conversation && this.conversationList.push(conversation) |
| | | this.conversationSort() |
| | | }, |
| | | /** 删除会话缓存 */ |
| | | deleteConversation(conversationId: number) { |
| | | const index = this.conversationList.findIndex((item) => item.id === conversationId) |
| | | // 存在则删除 |
| | | if (index > -1) { |
| | | this.conversationList.splice(index, 1) |
| | | } |
| | | }, |
| | | conversationSort() { |
| | | // 按置顶属性和最后消息时间排序 |
| | | this.conversationList.sort((a, b) => { |
| | | // 按照置顶排序,置顶的会在前面 |
| | | if (a.adminPinned !== b.adminPinned) { |
| | | return a.adminPinned ? -1 : 1 |
| | | } |
| | | // 按照最后消息时间排序,最近的会在前面 |
| | | return (b.lastMessageTime as unknown as number) - (a.lastMessageTime as unknown as number) |
| | | }) |
| | | } |
| | | } |
| | | }) |
| | | |
| | | export const useMallKefuStoreWithOut = () => { |
| | | return useMallKefuStore(store) |
| | | } |
对比新文件 |
| | |
| | | <template> |
| | | <ContentWrap> |
| | | <!-- 搜索工作栏 --> |
| | | <el-form |
| | | class="-mb-15px" |
| | | :model="queryParams" |
| | | ref="queryFormRef" |
| | | :inline="true" |
| | | label-width="68px" |
| | | > |
| | | <!-- <el-form-item label="主机名称" prop="hostName">--> |
| | | <!-- <el-input--> |
| | | <!-- v-model="queryParams.hostName"--> |
| | | <!-- placeholder="请输入主机名称"--> |
| | | <!-- clearable--> |
| | | <!-- @keyup.enter="handleQuery"--> |
| | | <!-- class="!w-240px"--> |
| | | <!-- />--> |
| | | <!-- </el-form-item>--> |
| | | <el-form-item label="服务器IP" prop="hostIp"> |
| | | <el-input |
| | | v-model="queryParams.hostIp" |
| | | placeholder="请输入服务器IP" |
| | | clearable |
| | | @keyup.enter="handleQuery" |
| | | class="!w-120px" |
| | | /> |
| | | </el-form-item> |
| | | <!-- <el-form-item label="盘符" prop="disk">--> |
| | | <!-- <el-input--> |
| | | <!-- v-model="queryParams.disk"--> |
| | | <!-- placeholder="请输入盘符"--> |
| | | <!-- clearable--> |
| | | <!-- @keyup.enter="handleQuery"--> |
| | | <!-- class="!w-240px"--> |
| | | <!-- />--> |
| | | <!-- </el-form-item>--> |
| | | <el-form-item label="磁盘名" prop="diskName"> |
| | | <el-input |
| | | v-model="queryParams.diskName" |
| | | placeholder="请输入磁盘名" |
| | | clearable |
| | | @keyup.enter="handleQuery" |
| | | class="!w-120px" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="创建时间" prop="createTime"> |
| | | <el-date-picker |
| | | v-model="queryParams.createTime" |
| | | value-format="YYYY-MM-DD HH:mm:ss" |
| | | type="datetimerange" |
| | | start-placeholder="开始日期" |
| | | end-placeholder="结束日期" |
| | | :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" |
| | | class="!w-360px" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button @click="handleQuery"> |
| | | <Icon icon="ep:search" class="mr-5px"/> |
| | | 搜索 |
| | | </el-button> |
| | | <el-button @click="resetQuery"> |
| | | <Icon icon="ep:refresh" class="mr-5px"/> |
| | | 重置 |
| | | </el-button> |
| | | <el-button |
| | | type="primary" |
| | | plain |
| | | @click="openForm('create')" |
| | | v-hasPermi="['infra:monitor-disk:create']" |
| | | > |
| | | <Icon icon="ep:plus" class="mr-5px"/> |
| | | 新增 |
| | | </el-button> |
| | | <el-button |
| | | type="success" |
| | | plain |
| | | @click="handleExport" |
| | | :loading="exportLoading" |
| | | v-hasPermi="['infra:monitor-disk:export']" |
| | | > |
| | | <Icon icon="ep:download" class="mr-5px"/> |
| | | 导出 |
| | | </el-button> |
| | | </el-form-item> |
| | | <el-form-item style="float: right"> |
| | | <el-button |
| | | v-if="showType == 'chart'" |
| | | type="warning" |
| | | style="font-weight: bold" |
| | | plain |
| | | @click="switchShow('data')"> |
| | | <Icon icon="fa-solid:th-list" class="mr-5px"/> |
| | | 列表展示 |
| | | </el-button> |
| | | <el-button |
| | | v-if="showType == 'data'" |
| | | type="danger" |
| | | style="font-weight: bold" |
| | | plain |
| | | @click="switchShow('chart')"> |
| | | <Icon icon="fa-solid:chart-pie" class="mr-5px"/> |
| | | 图例展示 |
| | | </el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </ContentWrap> |
| | | |
| | | <ContentWrap v-if="showType == 'chart'"> |
| | | <!-- 磁盘使用率折线图 --> |
| | | <el-skeleton :loading="echartsLoading" animated> |
| | | <Echart :height="320" :options="diskChartOptions"/> |
| | | </el-skeleton> |
| | | <!-- 磁盘使用率饼图 --> |
| | | <h3 style="margin-top: 20px; margin-bottom: 10px">主机磁盘使用率</h3> |
| | | <div v-for="host in hostList" :key="host.name" class="host"> |
| | | <div class="host-child"> |
| | | <h4>主机名:{{ host.name }} 主机IP:{{ host.ip }}</h4> |
| | | <el-skeleton :loading="echartsLoading" animated> |
| | | <div class="disks"> |
| | | <div v-for="disk in host.disks" :key="disk.name" class="disk"> |
| | | <h4 id="diskTitle">{{ disk.disk }}</h4> |
| | | <PieChart :used="disk.used" :total="disk.total" /> |
| | | <div class="disk-info"> |
| | | <div style="margin-bottom: 6px; font-size: 16px"><span style="color: #b9292b ;font-weight: bolder">{{ disk.total != 0 ? ((disk.used / disk.total) * 100).toFixed(1) : 0.0 }}% </span>已使用</div> |
| | | <div style="font-weight: bolder">{{ disk.used }}GB / {{ disk.total }}GB</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-skeleton> |
| | | </div> |
| | | </div> |
| | | <!-- <div v-for="(host, hostIndex) in hostList" :key="hostIndex">--> |
| | | <!-- <div style="margin-top: 10px">--> |
| | | <!-- <el-skeleton :loading="echartsLoading" animated>--> |
| | | <!-- {{ hostIndex }} 主机名: {{ host.name }} --> |
| | | <!-- 服务器IP:{{ host.ip }}--> |
| | | <!-- <div v-for="(disk, diskIndex) in host.disks" :key="diskIndex">--> |
| | | <!-- <h3>{{ disk.name }}</h3>--> |
| | | <!-- <div :ref="el => chartRefs[hostIndex][diskIndex] = el"--> |
| | | <!-- :style="{ width: '300px', height: '300px' }"></div>--> |
| | | <!-- </div>--> |
| | | <!-- </el-skeleton>--> |
| | | <!-- </div>--> |
| | | <!-- </div>--> |
| | | </ContentWrap> |
| | | |
| | | <!-- 列表 --> |
| | | <ContentWrap v-if="showType == 'data'"> |
| | | <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> |
| | | <el-table-column label="主机名称" align="center" prop="hostName"/> |
| | | <el-table-column label="服务器ip" align="center" prop="hostIp"/> |
| | | <el-table-column label="盘符" align="center" prop="disk"/> |
| | | <el-table-column label="磁盘名" align="center" prop="diskName"/> |
| | | <el-table-column label="总空间" align="center" prop="spaceTotal"/> |
| | | <el-table-column label="已用空间" align="center" prop="spaceUsed"/> |
| | | <el-table-column label="可用空间" align="center" prop="spaceUsable"/> |
| | | <el-table-column label="空间使用比例" align="center" prop="spaceRatio"/> |
| | | <el-table-column |
| | | label="创建时间" |
| | | align="center" |
| | | prop="createTime" |
| | | :formatter="dateFormatter" |
| | | width="180px" |
| | | /> |
| | | <el-table-column label="操作" align="center"> |
| | | <template #default="scope"> |
| | | <el-button |
| | | link |
| | | type="primary" |
| | | @click="openForm('update', scope.row.id)" |
| | | v-hasPermi="['infra:monitor-disk:query']" |
| | | > |
| | | 详情 |
| | | </el-button> |
| | | <el-button |
| | | link |
| | | type="danger" |
| | | @click="handleDelete(scope.row.id)" |
| | | v-hasPermi="['infra:monitor-disk:delete']" |
| | | > |
| | | 删除 |
| | | </el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <!-- 分页 --> |
| | | <Pagination |
| | | :total="total" |
| | | v-model:page="queryParams.pageNo" |
| | | v-model:limit="queryParams.pageSize" |
| | | @pagination="getList" |
| | | /> |
| | | </ContentWrap> |
| | | |
| | | <!-- 表单弹窗:添加/修改 --> |
| | | <MonitorDiskForm ref="formRef" @success="getList"/> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import {dateFormatter} from '@/utils/formatTime' |
| | | import download from '@/utils/download' |
| | | import {MonitorDiskApi, MonitorDiskVO} from '@/api/infra/monitordisk' |
| | | import MonitorDiskForm from './MonitorDiskForm.vue' |
| | | import {EChartsOption} from "echarts"; |
| | | import * as echarts from 'echarts'; |
| | | import {formatTime} from "@/utils"; |
| | | import {formatDate} from "@vueuse/core"; |
| | | import PieChart from '@/components/MonitorDiskPie/PieChart.vue'; |
| | | |
| | | /** 磁盘监控日志 列表 */ |
| | | defineOptions({name: 'MonitorDisk'}) |
| | | |
| | | const message = useMessage() // 消息弹窗 |
| | | const {t} = useI18n() // 国际化 |
| | | |
| | | const loading = ref(true) // 列表的加载中 |
| | | const list = ref<MonitorDiskVO[]>([]) // 列表的数据 |
| | | const total = ref(0) // 列表的总页数 |
| | | const queryParams = reactive({ |
| | | pageNo: 1, |
| | | pageSize: 10, |
| | | hostName: undefined, |
| | | hostIp: undefined, |
| | | disk: undefined, |
| | | diskName: undefined, |
| | | spaceTotal: undefined, |
| | | spaceUsed: undefined, |
| | | spaceUsable: undefined, |
| | | spaceRatio: undefined, |
| | | createTime: [], |
| | | }) |
| | | const queryFormRef = ref() // 搜索的表单 |
| | | const exportLoading = ref(false) // 导出的加载中 |
| | | const echartsLoading = ref(true) // 图表加载中 |
| | | const showType = ref() //展示类型(chart-图例,data-数据) |
| | | |
| | | const hostList = ref([ |
| | | { |
| | | name: 'Thinkpad-E14', |
| | | ip: '172.16.216.133', |
| | | disks: [ |
| | | {disk: '磁盘C', used: 70, total: 200}, |
| | | {disk: '磁盘D', used: 40, total: 60} |
| | | ] |
| | | }, |
| | | { |
| | | name: 'Thinkpad-E16', |
| | | ip: '172.16.216.133', |
| | | disks: [ |
| | | {disk: '磁盘C', used: 80, total: 500}, |
| | | {disk: '磁盘D', used: 20, total: 500} |
| | | ] |
| | | } |
| | | ]); |
| | | |
| | | const chartRefs = ref([]); |
| | | |
| | | /** 查询列表 */ |
| | | const getList = async () => { |
| | | loading.value = true |
| | | try { |
| | | const data = await MonitorDiskApi.getMonitorDiskPage(queryParams) |
| | | list.value = data.list |
| | | total.value = data.total |
| | | } finally { |
| | | loading.value = false |
| | | } |
| | | } |
| | | |
| | | /** 搜索按钮操作 */ |
| | | const handleQuery = () => { |
| | | queryParams.pageNo = 1 |
| | | if (showType.value == 'data') { |
| | | getList() |
| | | } else { |
| | | getMonitorDiskDataList() |
| | | usedDiskInstance() |
| | | } |
| | | } |
| | | |
| | | /** 重置按钮操作 */ |
| | | const resetQuery = () => { |
| | | queryFormRef.value.resetFields() |
| | | handleQuery() |
| | | } |
| | | |
| | | /** 添加/修改操作 */ |
| | | const formRef = ref() |
| | | const openForm = (type: string, id?: number) => { |
| | | formRef.value.open(type, id) |
| | | } |
| | | |
| | | /** 删除按钮操作 */ |
| | | const handleDelete = async (id: number) => { |
| | | try { |
| | | // 删除的二次确认 |
| | | await message.delConfirm() |
| | | // 发起删除 |
| | | await MonitorDiskApi.deleteMonitorDisk(id) |
| | | message.success(t('common.delSuccess')) |
| | | // 刷新列表 |
| | | await getList() |
| | | } catch { |
| | | } |
| | | } |
| | | |
| | | /** 导出按钮操作 */ |
| | | const handleExport = async () => { |
| | | try { |
| | | // 导出的二次确认 |
| | | await message.exportConfirm() |
| | | // 发起导出 |
| | | exportLoading.value = true |
| | | const data = await MonitorDiskApi.exportMonitorDisk(queryParams) |
| | | download.excel(data, '磁盘监控日志.xls') |
| | | } catch { |
| | | } finally { |
| | | exportLoading.value = false |
| | | } |
| | | } |
| | | |
| | | /** 堆叠面积图配置 */ |
| | | const diskChartOptions = reactive<EChartsOption>({ |
| | | title: { |
| | | text: '磁盘空间折线图' |
| | | }, |
| | | dataset: { |
| | | dimensions: [], |
| | | source: [] |
| | | }, |
| | | grid: { |
| | | left: 30, |
| | | right: 20, |
| | | bottom: 10, |
| | | top: 70, |
| | | containLabel: true |
| | | }, |
| | | legend: { |
| | | top: 0 |
| | | }, |
| | | series: [ |
| | | { |
| | | name: 'disk', type: 'line', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, smooth: false |
| | | } |
| | | ], |
| | | toolbox: { |
| | | feature: { |
| | | // 数据区域缩放 |
| | | dataZoom: { |
| | | yAxisIndex: false // Y轴不缩放 |
| | | }, |
| | | brush: { |
| | | type: ['lineX', 'clear'] // 区域缩放按钮、还原按钮 |
| | | }, |
| | | saveAsImage: {show: true, name: '物理内存日志图片'} // 保存为图片 |
| | | } |
| | | }, |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | axisPointer: { |
| | | type: 'cross', |
| | | label: { |
| | | backgroundColor: '#6a7985' |
| | | } |
| | | }, |
| | | padding: [5, 10] |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | boundaryGap: false, |
| | | axisTick: { |
| | | show: false |
| | | } |
| | | }, |
| | | yAxis: { |
| | | name: "单位(百分比)", |
| | | nameTextStyle: { |
| | | color: "#aaa", |
| | | nameLocation: "start", |
| | | }, |
| | | }, |
| | | }) as EChartsOption |
| | | |
| | | /** 查询统计数据列表 */ |
| | | const getMonitorDiskDataList = async () => { |
| | | const list = await MonitorDiskApi.getMonitorDiskList(queryParams) |
| | | if (list != null && list != undefined && list.length > 0) { |
| | | diskChartOptions.dataset['dimensions'] = Object.keys(list[0]) |
| | | diskChartOptions.series = diskChartOptions.dataset['dimensions'].map(item => ({ |
| | | name: item.name, |
| | | type: 'line', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | smooth: false |
| | | })); |
| | | diskChartOptions.series.splice(0, 1) |
| | | for (let item of list) { |
| | | item.createTime = formatTime(item.createTime, 'yyyy-MM-dd HH:mm:ss') |
| | | } |
| | | } |
| | | // 更新 Echarts 数据 |
| | | diskChartOptions.dataset['source'] = list |
| | | echartsLoading.value = false |
| | | } |
| | | |
| | | const usedDiskInstance = async () => { |
| | | const list = await MonitorDiskApi.getMonitorDiskInfo(queryParams) |
| | | hostList.value = list |
| | | // 仪表盘详情,用于显示数据。 |
| | | } |
| | | |
| | | /** 切换展示方式 */ |
| | | const switchShow = (type: String) => { |
| | | showType.value = type |
| | | if (showType.value == 'data') { |
| | | getList() |
| | | } else { |
| | | getMonitorDiskDataList() |
| | | usedDiskInstance() |
| | | } |
| | | } |
| | | |
| | | let intervalId; |
| | | /** 初始化 **/ |
| | | onMounted(() => { |
| | | showType.value = 'data'; |
| | | const currentDate = new Date(); |
| | | const previousDate = new Date(currentDate); |
| | | previousDate.setDate(currentDate.getDate() - 1); |
| | | queryParams.createTime[0] = formatDate(previousDate, 'YYYY-MM-DD HH:mm:ss'); |
| | | queryParams.createTime[1] = formatDate(currentDate, 'YYYY-MM-DD HH:mm:ss'); |
| | | intervalId = setInterval(() => { |
| | | if (showType.value == 'data') { |
| | | getList() |
| | | } else { |
| | | getMonitorDiskDataList() |
| | | usedDiskInstance() |
| | | } |
| | | }, 30000); |
| | | }) |
| | | |
| | | onUnmounted(() => { |
| | | clearInterval(intervalId); |
| | | }); |
| | | </script> |
| | | <style> |
| | | .host { |
| | | margin-bottom: 20px; |
| | | margin-right: 20px; |
| | | border-radius: 8px; |
| | | } |
| | | .host-child { |
| | | background: rgba(200, 200, 200, 0.3); |
| | | border-radius: 8px; |
| | | padding: 10px; |
| | | } |
| | | .disks { |
| | | display: grid; |
| | | grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); |
| | | gap: 20px; |
| | | margin-top: 20px; |
| | | } |
| | | .disk { |
| | | width: 250px; |
| | | background: rgba(100, 100, 150, 0.2); |
| | | padding: 15px; |
| | | border-radius: 16px; |
| | | text-align: center; |
| | | box-shadow: 0 2px 4px rgba(0,0,0,0.1); |
| | | } |
| | | |
| | | #diskTitle { |
| | | margin-bottom: 10px |
| | | } |
| | | |
| | | .disk-info { |
| | | margin-top: 10px; |
| | | font-size: 0.9em; |
| | | color: #666; |
| | | } |
| | | </style> |
对比新文件 |
| | |
| | | <template> |
| | | <Dialog :title="dialogTitle" v-model="dialogVisible"> |
| | | <el-form |
| | | ref="formRef" |
| | | :model="formData" |
| | | :rules="formRules" |
| | | label-width="100px" |
| | | v-loading="formLoading" |
| | | > |
| | | <el-form-item label="主机名称" prop="hostName"> |
| | | <el-input v-model="formData.hostName" placeholder="请输入主机名称" /> |
| | | </el-form-item> |
| | | <el-form-item label="服务器ip" prop="hostIp"> |
| | | <el-input v-model="formData.hostIp" placeholder="请输入服务器ip" /> |
| | | </el-form-item> |
| | | <el-form-item label="盘符" prop="disk"> |
| | | <el-input v-model="formData.disk" placeholder="请输入盘符" /> |
| | | </el-form-item> |
| | | <el-form-item label="磁盘名" prop="diskName"> |
| | | <el-input v-model="formData.diskName" placeholder="请输入磁盘名" /> |
| | | </el-form-item> |
| | | <el-form-item label="总空间" prop="spaceTotal"> |
| | | <el-input v-model="formData.spaceTotal" placeholder="请输入总空间" /> |
| | | </el-form-item> |
| | | <el-form-item label="已用空间" prop="spaceUsed"> |
| | | <el-input v-model="formData.spaceUsed" placeholder="请输入已用空间" /> |
| | | </el-form-item> |
| | | <el-form-item label="可用空间" prop="spaceUsable"> |
| | | <el-input v-model="formData.spaceUsable" placeholder="请输入可用空间" /> |
| | | </el-form-item> |
| | | <el-form-item label="空间使用比例" prop="spaceRatio"> |
| | | <el-input v-model="formData.spaceRatio" placeholder="请输入空间使用比例" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> |
| | | <el-button @click="dialogVisible = false">取 消</el-button> |
| | | </template> |
| | | </Dialog> |
| | | </template> |
| | | <script setup lang="ts"> |
| | | import { MonitorDiskApi, MonitorDiskVO } from '@/api/infra/monitordisk' |
| | | |
| | | /** 磁盘监控日志 表单 */ |
| | | defineOptions({ name: 'MonitorDiskForm' }) |
| | | |
| | | const { t } = useI18n() // 国际化 |
| | | const message = useMessage() // 消息弹窗 |
| | | |
| | | const dialogVisible = ref(false) // 弹窗的是否展示 |
| | | const dialogTitle = ref('') // 弹窗的标题 |
| | | const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 |
| | | const formType = ref('') // 表单的类型:create - 新增;update - 修改 |
| | | const formData = ref({ |
| | | id: undefined, |
| | | hostName: undefined, |
| | | hostIp: undefined, |
| | | disk: undefined, |
| | | diskName: undefined, |
| | | spaceTotal: undefined, |
| | | spaceUsed: undefined, |
| | | spaceUsable: undefined, |
| | | spaceRatio: undefined, |
| | | }) |
| | | const formRules = reactive({ |
| | | hostName: [{ required: true, message: '主机名称不能为空', trigger: 'blur' }], |
| | | hostIp: [{ required: true, message: '服务器ip不能为空', trigger: 'blur' }], |
| | | }) |
| | | const formRef = ref() // 表单 Ref |
| | | |
| | | /** 打开弹窗 */ |
| | | const open = async (type: string, id?: number) => { |
| | | dialogVisible.value = true |
| | | dialogTitle.value = t('action.' + type) |
| | | formType.value = type |
| | | resetForm() |
| | | // 修改时,设置数据 |
| | | if (id) { |
| | | formLoading.value = true |
| | | try { |
| | | formData.value = await MonitorDiskApi.getMonitorDisk(id) |
| | | } finally { |
| | | formLoading.value = false |
| | | } |
| | | } |
| | | } |
| | | defineExpose({ open }) // 提供 open 方法,用于打开弹窗 |
| | | |
| | | /** 提交表单 */ |
| | | const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 |
| | | const submitForm = async () => { |
| | | // 校验表单 |
| | | await formRef.value.validate() |
| | | // 提交请求 |
| | | formLoading.value = true |
| | | try { |
| | | const data = formData.value as unknown as MonitorDiskVO |
| | | if (formType.value === 'create') { |
| | | await MonitorDiskApi.createMonitorDisk(data) |
| | | message.success(t('common.createSuccess')) |
| | | } else { |
| | | await MonitorDiskApi.updateMonitorDisk(data) |
| | | message.success(t('common.updateSuccess')) |
| | | } |
| | | dialogVisible.value = false |
| | | // 发送操作成功的事件 |
| | | emit('success') |
| | | } finally { |
| | | formLoading.value = false |
| | | } |
| | | } |
| | | |
| | | /** 重置表单 */ |
| | | const resetForm = () => { |
| | | formData.value = { |
| | | id: undefined, |
| | | hostName: undefined, |
| | | hostIp: undefined, |
| | | disk: undefined, |
| | | diskName: undefined, |
| | | spaceTotal: undefined, |
| | | spaceUsed: undefined, |
| | | spaceUsable: undefined, |
| | | spaceRatio: undefined, |
| | | } |
| | | formRef.value?.resetFields() |
| | | } |
| | | </script> |
对比新文件 |
| | |
| | | <template> |
| | | <ContentWrap> |
| | | <!-- 搜索工作栏 --> |
| | | <el-form |
| | | class="-mb-15px" |
| | | :model="queryParams" |
| | | ref="queryFormRef" |
| | | :inline="true" |
| | | label-width="68px" |
| | | > |
| | | <!-- <el-form-item label="主机名称" prop="hostName">--> |
| | | <!-- <el-input--> |
| | | <!-- v-model="queryParams.hostName"--> |
| | | <!-- placeholder="请输入主机名称"--> |
| | | <!-- clearable--> |
| | | <!-- @keyup.enter="handleQuery"--> |
| | | <!-- class="!w-120px"--> |
| | | <!-- />--> |
| | | <!-- </el-form-item>--> |
| | | <el-form-item label="服务器IP" prop="hostIp"> |
| | | <el-input |
| | | v-model="queryParams.hostIp" |
| | | placeholder="请输入服务器IP" |
| | | clearable |
| | | @keyup.enter="handleQuery" |
| | | class="!w-120px" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="服务名" prop="serverName"> |
| | | <el-input |
| | | v-model="queryParams.serverName" |
| | | placeholder="请输入服务名" |
| | | clearable |
| | | @keyup.enter="handleQuery" |
| | | class="!w-120px" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="创建时间" prop="createTime"> |
| | | <el-date-picker |
| | | v-model="queryParams.createTime" |
| | | value-format="YYYY-MM-DD HH:mm:ss" |
| | | type="datetimerange" |
| | | start-placeholder="开始日期" |
| | | end-placeholder="结束日期" |
| | | :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" |
| | | class="!w-360px" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button @click="handleQuery"> |
| | | <Icon icon="ep:search" class="mr-5px"/> |
| | | 搜索 |
| | | </el-button> |
| | | <el-button @click="resetQuery"> |
| | | <Icon icon="ep:refresh" class="mr-5px"/> |
| | | 重置 |
| | | </el-button> |
| | | <el-button |
| | | type="primary" |
| | | plain |
| | | @click="openForm('create')" |
| | | v-hasPermi="['infra:monitor-mem:create']" |
| | | > |
| | | <Icon icon="ep:plus" class="mr-5px"/> |
| | | 新增 |
| | | </el-button> |
| | | <el-button |
| | | type="success" |
| | | plain |
| | | @click="handleExport" |
| | | :loading="exportLoading" |
| | | v-hasPermi="['infra:monitor-mem:export']" |
| | | > |
| | | <Icon icon="ep:download" class="mr-5px"/> |
| | | 导出 |
| | | </el-button> |
| | | </el-form-item> |
| | | <el-form-item style="float: right"> |
| | | <el-button |
| | | v-if="showType == 'chart'" |
| | | type="warning" |
| | | style="font-weight: bold" |
| | | plain |
| | | @click="switchShow('data')"> |
| | | <Icon icon="fa-solid:th-list" class="mr-5px"/> |
| | | 列表展示 |
| | | </el-button> |
| | | <el-button |
| | | v-if="showType == 'data'" |
| | | type="danger" |
| | | style="font-weight: bold" |
| | | plain |
| | | @click="switchShow('chart')"> |
| | | <Icon icon="fa-solid:chart-pie" class="mr-5px"/> |
| | | 图例展示 |
| | | </el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </ContentWrap> |
| | | |
| | | <ContentWrap v-if="showType == 'chart'"> |
| | | <!-- 物理内存折线图 --> |
| | | <el-skeleton :loading="echartsLoading" animated> |
| | | <Echart :height="320" :options="physicalChartOptions"/> |
| | | </el-skeleton> |
| | | <!-- JVM内存折线图 --> |
| | | <el-skeleton :loading="echartsLoading" animated> |
| | | <Echart style="margin-top: 20px" :height="320" :options="JVMChartOptions"/> |
| | | </el-skeleton> |
| | | </ContentWrap> |
| | | |
| | | <!-- 列表 --> |
| | | <ContentWrap v-if="showType == 'data'"> |
| | | <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> |
| | | <el-table-column label="主机名称" align="center" prop="hostName"/> |
| | | <el-table-column label="服务器ip" align="center" prop="hostIp"/> |
| | | <el-table-column label="服务名" align="center" prop="serverName" width="120"/> |
| | | <el-table-column label="总内存" align="center" prop="physicalTotal"/> |
| | | <el-table-column label="已用内存" align="center" prop="physicalUsed"/> |
| | | <el-table-column label="空闲内存" align="center" prop="physicalFree"/> |
| | | <el-table-column label="内存使用率" align="center" prop="physicalUsage" width="100"/> |
| | | <el-table-column label="JVM占用内存" align="center" prop="runtimeTotal"/> |
| | | <el-table-column label="JVM最大内存" align="center" prop="runtimeMax"/> |
| | | <el-table-column label="JVM可用内存" align="center" prop="runtimeUsed"/> |
| | | <el-table-column label="JVM空闲内存" align="center" prop="runtimeFree"/> |
| | | <el-table-column label="JVM内存使用率" align="center" prop="runtimeUsage"/> |
| | | <el-table-column |
| | | label="创建时间" |
| | | align="center" |
| | | prop="createTime" |
| | | :formatter="dateFormatter" |
| | | width="180px" |
| | | /> |
| | | <el-table-column label="操作" align="center"> |
| | | <template #default="scope"> |
| | | <el-button |
| | | link |
| | | type="primary" |
| | | @click="openForm('update', scope.row.id)" |
| | | v-hasPermi="['infra:monitor-mem:query']" |
| | | > |
| | | 详情 |
| | | </el-button> |
| | | <el-button |
| | | link |
| | | type="danger" |
| | | @click="handleDelete(scope.row.id)" |
| | | v-hasPermi="['infra:monitor-mem:delete']" |
| | | > |
| | | 删除 |
| | | </el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <!-- 分页 --> |
| | | <Pagination |
| | | :total="total" |
| | | v-model:page="queryParams.pageNo" |
| | | v-model:limit="queryParams.pageSize" |
| | | @pagination="getList" |
| | | /> |
| | | </ContentWrap> |
| | | |
| | | <!-- 表单弹窗:添加/修改 --> |
| | | <MonitorMemForm ref="formRef" @success="getList"/> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import {dateFormatter} from '@/utils/formatTime' |
| | | import download from '@/utils/download' |
| | | import {MonitorMemApi, MonitorMemVO} from '@/api/infra/monitormem' |
| | | import MonitorMemForm from './MonitorMemForm.vue' |
| | | import {EChartsOption} from "echarts"; |
| | | import {formatTime} from "@/utils"; |
| | | import {formatDate} from "@vueuse/core"; |
| | | |
| | | /** 内存监控日志 列表 */ |
| | | defineOptions({name: 'MonitorMem'}) |
| | | |
| | | const message = useMessage() // 消息弹窗 |
| | | const {t} = useI18n() // 国际化 |
| | | |
| | | const loading = ref(true) // 列表的加载中 |
| | | const list = ref<MonitorMemVO[]>([]) // 列表的数据 |
| | | const total = ref(0) // 列表的总页数 |
| | | const queryParams = reactive({ |
| | | pageNo: 1, |
| | | pageSize: 10, |
| | | hostName: undefined, |
| | | hostIp: undefined, |
| | | serverName: undefined, |
| | | physicalTotal: undefined, |
| | | physicalUsed: undefined, |
| | | physicalFree: undefined, |
| | | physicalUsage: undefined, |
| | | runtimeTotal: undefined, |
| | | runtimeMax: undefined, |
| | | runtimeUsed: undefined, |
| | | runtimeFree: undefined, |
| | | runtimeUsage: undefined, |
| | | createTime: [], |
| | | }) |
| | | const queryFormRef = ref() // 搜索的表单 |
| | | const exportLoading = ref(false) // 导出的加载中 |
| | | const echartsLoading = ref(true) // 图表加载中 |
| | | const showType = ref() //展示类型(chart-图例,data-数据) |
| | | |
| | | /** 查询列表 */ |
| | | const getList = async () => { |
| | | loading.value = true |
| | | try { |
| | | const data = await MonitorMemApi.getMonitorMemPage(queryParams) |
| | | list.value = data.list |
| | | total.value = data.total |
| | | } finally { |
| | | loading.value = false |
| | | } |
| | | } |
| | | |
| | | /** 搜索按钮操作 */ |
| | | const handleQuery = () => { |
| | | queryParams.pageNo = 1 |
| | | if(showType.value == 'data') { |
| | | getList() |
| | | } else { |
| | | getMonitorMemDataList() |
| | | } |
| | | } |
| | | |
| | | /** 重置按钮操作 */ |
| | | const resetQuery = () => { |
| | | queryFormRef.value.resetFields() |
| | | handleQuery() |
| | | } |
| | | |
| | | /** 添加/修改操作 */ |
| | | const formRef = ref() |
| | | const openForm = (type: string, id?: number) => { |
| | | formRef.value.open(type, id) |
| | | } |
| | | |
| | | /** 删除按钮操作 */ |
| | | const handleDelete = async (id: number) => { |
| | | try { |
| | | // 删除的二次确认 |
| | | await message.delConfirm() |
| | | // 发起删除 |
| | | await MonitorMemApi.deleteMonitorMem(id) |
| | | message.success(t('common.delSuccess')) |
| | | // 刷新列表 |
| | | await getList() |
| | | } catch { |
| | | } |
| | | } |
| | | |
| | | /** 堆叠面积图配置 */ |
| | | const physicalChartOptions = reactive<EChartsOption>({ |
| | | title: { |
| | | text: '物理内存折线图' |
| | | }, |
| | | dataset: { |
| | | dimensions: ['createTime', 'physicalTotal', 'physicalUsed', 'physicalFree'], |
| | | source: [] |
| | | }, |
| | | grid: { |
| | | left: 20, |
| | | right: 20, |
| | | bottom: 10, |
| | | top: 70, |
| | | containLabel: true |
| | | }, |
| | | legend: { |
| | | top: 0 |
| | | }, |
| | | series: [ |
| | | { |
| | | name: '总物理内存', type: 'line', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, smooth: false |
| | | }, |
| | | { |
| | | name: '已用物理内存', type: 'line', areaStyle: {}, |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, smooth: false |
| | | }, |
| | | { |
| | | name: '剩余物理内存', type: 'line', areaStyle: {}, |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, smooth: false |
| | | } |
| | | ], |
| | | toolbox: { |
| | | feature: { |
| | | // 数据区域缩放 |
| | | dataZoom: { |
| | | yAxisIndex: false // Y轴不缩放 |
| | | }, |
| | | brush: { |
| | | type: ['lineX', 'clear'] // 区域缩放按钮、还原按钮 |
| | | }, |
| | | saveAsImage: {show: true, name: '物理内存日志图片'} // 保存为图片 |
| | | } |
| | | }, |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | axisPointer: { |
| | | type: 'cross', |
| | | label: { |
| | | backgroundColor: '#6a7985' |
| | | } |
| | | }, |
| | | padding: [5, 10] |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | boundaryGap: false, |
| | | axisTick: { |
| | | show: false |
| | | } |
| | | }, |
| | | yAxis: { |
| | | name: "单位(MB)", |
| | | nameTextStyle: { |
| | | color: "#aaa", |
| | | nameLocation: "start", |
| | | }, |
| | | }, |
| | | }) as EChartsOption |
| | | |
| | | /** 堆叠面积图配置 */ |
| | | const JVMChartOptions = reactive<EChartsOption>({ |
| | | title: { |
| | | text: 'JVM内存折线图' |
| | | }, |
| | | dataset: { |
| | | dimensions: ['createTime', 'runtimeMax', 'runtimeTotal', 'runtimeUsed', 'runtimeFree'], |
| | | source: [] |
| | | }, |
| | | grid: { |
| | | left: 20, |
| | | right: 20, |
| | | bottom: 0, |
| | | top: 70, |
| | | containLabel: true |
| | | }, |
| | | legend: { |
| | | top: 0 |
| | | }, |
| | | series: [ |
| | | { |
| | | name: 'JVM最大内存', type: 'line', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, smooth: false |
| | | }, |
| | | { |
| | | name: 'JVM占用内存', type: 'line', |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, smooth: false |
| | | }, |
| | | { |
| | | name: 'JVM可用内存', type: 'line', areaStyle: {}, |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, smooth: false |
| | | }, |
| | | { |
| | | name: 'JVM空闲内存', type: 'line', areaStyle: {}, |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, smooth: false |
| | | } |
| | | ], |
| | | toolbox: { |
| | | feature: { |
| | | // 数据区域缩放 |
| | | dataZoom: { |
| | | yAxisIndex: false // Y轴不缩放 |
| | | }, |
| | | brush: { |
| | | type: ['lineX', 'clear'] // 区域缩放按钮、还原按钮 |
| | | }, |
| | | saveAsImage: {show: true, name: 'JVM内存日志图片'} // 保存为图片 |
| | | } |
| | | }, |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | axisPointer: { |
| | | type: 'cross', |
| | | label: { |
| | | backgroundColor: '#6a7985' |
| | | } |
| | | }, |
| | | padding: [5, 10] |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | boundaryGap: false, |
| | | axisTick: { |
| | | show: false |
| | | } |
| | | }, |
| | | yAxis: { |
| | | name: "单位(MB)", |
| | | nameTextStyle: { |
| | | color: "#aaa", |
| | | nameLocation: "start", |
| | | }, |
| | | }, |
| | | }) as EChartsOption |
| | | |
| | | /** 查询统计数据列表 */ |
| | | const getMonitorMemDataList = async () => { |
| | | const list = await MonitorMemApi.getMonitorMemList(queryParams) |
| | | for (let item of list) { |
| | | item.createTime = formatTime(item.createTime, 'yyyy-MM-dd HH:mm:ss') |
| | | } |
| | | // 更新 Echarts 数据 |
| | | if (physicalChartOptions.dataset && physicalChartOptions.dataset['source']) { |
| | | physicalChartOptions.dataset['source'] = list |
| | | } |
| | | if (JVMChartOptions.dataset && JVMChartOptions.dataset['source']) { |
| | | JVMChartOptions.dataset['source'] = list |
| | | } |
| | | echartsLoading.value = false |
| | | } |
| | | |
| | | /** 切换展示方式 */ |
| | | const switchShow = (type: String) => { |
| | | showType.value = type |
| | | if(showType.value == 'data') { |
| | | getList() |
| | | } else { |
| | | getMonitorMemDataList() |
| | | } |
| | | } |
| | | |
| | | /** 导出按钮操作 */ |
| | | const handleExport = async () => { |
| | | try { |
| | | // 导出的二次确认 |
| | | await message.exportConfirm() |
| | | // 发起导出 |
| | | exportLoading.value = true |
| | | const data = await MonitorMemApi.exportMonitorMem(queryParams) |
| | | download.excel(data, '内存监控日志.xls') |
| | | } catch { |
| | | } finally { |
| | | exportLoading.value = false |
| | | } |
| | | } |
| | | |
| | | let intervalId; |
| | | /** 初始化 **/ |
| | | onMounted(() => { |
| | | showType.value = 'data'; |
| | | const currentDate = new Date(); |
| | | const previousDate = new Date(currentDate); |
| | | previousDate.setDate(currentDate.getDate() - 1); |
| | | queryParams.createTime[0] = formatDate(previousDate, 'YYYY-MM-DD HH:mm:ss'); |
| | | queryParams.createTime[1] = formatDate(currentDate, 'YYYY-MM-DD HH:mm:ss'); |
| | | intervalId = setInterval(() => { |
| | | if(showType.value == 'data') { |
| | | getList() |
| | | } else { |
| | | getMonitorMemDataList() |
| | | } |
| | | }, 60000); |
| | | }) |
| | | |
| | | onUnmounted(() => { |
| | | clearInterval(intervalId); |
| | | }); |
| | | </script> |
对比新文件 |
| | |
| | | <template> |
| | | <Dialog :title="dialogTitle" v-model="dialogVisible"> |
| | | <el-form |
| | | ref="formRef" |
| | | :model="formData" |
| | | :rules="formRules" |
| | | label-width="100px" |
| | | v-loading="formLoading" |
| | | > |
| | | <el-form-item label="主机名称" prop="hostName"> |
| | | <el-input v-model="formData.hostName" placeholder="请输入主机名称" /> |
| | | </el-form-item> |
| | | <el-form-item label="服务器ip" prop="hostIp"> |
| | | <el-input v-model="formData.hostIp" placeholder="请输入服务器ip" /> |
| | | </el-form-item> |
| | | <el-form-item label="服务名" prop="serverName"> |
| | | <el-input v-model="formData.serverName" placeholder="请输入服务名" /> |
| | | </el-form-item> |
| | | <el-form-item label="总内存" prop="physicalTotal"> |
| | | <el-input v-model="formData.physicalTotal" placeholder="请输入总物理内存" /> |
| | | </el-form-item> |
| | | <el-form-item label="已用内存" prop="physicalUsed"> |
| | | <el-input v-model="formData.physicalUsed" placeholder="请输入已用物理内存" /> |
| | | </el-form-item> |
| | | <el-form-item label="空闲内存" prop="physicalFree"> |
| | | <el-input v-model="formData.physicalFree" placeholder="请输入空闲内存" /> |
| | | </el-form-item> |
| | | <el-form-item label="内存使用率" prop="physicalUsage"> |
| | | <el-input v-model="formData.physicalUsage" placeholder="请输入物理内存使用率" /> |
| | | </el-form-item> |
| | | <el-form-item label="jvm运行总内存" prop="runtimeTotal"> |
| | | <el-input v-model="formData.runtimeTotal" placeholder="请输入jvm运行总内存" /> |
| | | </el-form-item> |
| | | <el-form-item label="jvm最大内存" prop="runtimeMax"> |
| | | <el-input v-model="formData.runtimeMax" placeholder="请输入jvm最大内存" /> |
| | | </el-form-item> |
| | | <el-form-item label="jvm已用内存" prop="runtimeUsed"> |
| | | <el-input v-model="formData.runtimeUsed" placeholder="请输入jvm已用内存" /> |
| | | </el-form-item> |
| | | <el-form-item label="jvm空闲内存" prop="runtimeFree"> |
| | | <el-input v-model="formData.runtimeFree" placeholder="请输入jvm空闲内存" /> |
| | | </el-form-item> |
| | | <el-form-item label="jvm内存使用率" prop="runtimeUsage"> |
| | | <el-input v-model="formData.runtimeUsage" placeholder="请输入jvm内存使用率" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> |
| | | <el-button @click="dialogVisible = false">取 消</el-button> |
| | | </template> |
| | | </Dialog> |
| | | </template> |
| | | <script setup lang="ts"> |
| | | import { MonitorMemApi, MonitorMemVO } from '@/api/infra/monitormem' |
| | | |
| | | /** 内存监控日志 表单 */ |
| | | defineOptions({ name: 'MonitorMemForm' }) |
| | | |
| | | const { t } = useI18n() // 国际化 |
| | | const message = useMessage() // 消息弹窗 |
| | | |
| | | const dialogVisible = ref(false) // 弹窗的是否展示 |
| | | const dialogTitle = ref('') // 弹窗的标题 |
| | | const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 |
| | | const formType = ref('') // 表单的类型:create - 新增;update - 修改 |
| | | const formData = ref({ |
| | | id: undefined, |
| | | hostName: undefined, |
| | | hostIp: undefined, |
| | | serverName: undefined, |
| | | physicalTotal: undefined, |
| | | physicalUsed: undefined, |
| | | physicalFree: undefined, |
| | | physicalUsage: undefined, |
| | | runtimeTotal: undefined, |
| | | runtimeMax: undefined, |
| | | runtimeUsed: undefined, |
| | | runtimeFree: undefined, |
| | | runtimeUsage: undefined, |
| | | }) |
| | | const formRules = reactive({ |
| | | hostName: [{ required: true, message: '主机名称不能为空', trigger: 'blur' }], |
| | | hostIp: [{ required: true, message: '服务器ip不能为空', trigger: 'blur' }], |
| | | }) |
| | | const formRef = ref() // 表单 Ref |
| | | |
| | | /** 打开弹窗 */ |
| | | const open = async (type: string, id?: number) => { |
| | | dialogVisible.value = true |
| | | dialogTitle.value = t('action.' + type) |
| | | formType.value = type |
| | | resetForm() |
| | | // 修改时,设置数据 |
| | | if (id) { |
| | | formLoading.value = true |
| | | try { |
| | | formData.value = await MonitorMemApi.getMonitorMem(id) |
| | | } finally { |
| | | formLoading.value = false |
| | | } |
| | | } |
| | | } |
| | | defineExpose({ open }) // 提供 open 方法,用于打开弹窗 |
| | | |
| | | /** 提交表单 */ |
| | | const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 |
| | | const submitForm = async () => { |
| | | // 校验表单 |
| | | await formRef.value.validate() |
| | | // 提交请求 |
| | | formLoading.value = true |
| | | try { |
| | | const data = formData.value as unknown as MonitorMemVO |
| | | if (formType.value === 'create') { |
| | | await MonitorMemApi.createMonitorMem(data) |
| | | message.success(t('common.createSuccess')) |
| | | } else { |
| | | await MonitorMemApi.updateMonitorMem(data) |
| | | message.success(t('common.updateSuccess')) |
| | | } |
| | | dialogVisible.value = false |
| | | // 发送操作成功的事件 |
| | | emit('success') |
| | | } finally { |
| | | formLoading.value = false |
| | | } |
| | | } |
| | | |
| | | /** 重置表单 */ |
| | | const resetForm = () => { |
| | | formData.value = { |
| | | id: undefined, |
| | | hostName: undefined, |
| | | hostIp: undefined, |
| | | serverName: undefined, |
| | | physicalTotal: undefined, |
| | | physicalUsed: undefined, |
| | | physicalFree: undefined, |
| | | physicalUsage: undefined, |
| | | runtimeTotal: undefined, |
| | | runtimeMax: undefined, |
| | | runtimeUsed: undefined, |
| | | runtimeFree: undefined, |
| | | runtimeUsage: undefined, |
| | | } |
| | | formRef.value?.resetFields() |
| | | } |
| | | </script> |
对比新文件 |
| | |
| | | import MonitorMem from './MonitorMem.vue' |
| | | import MonitorDisk from './MonitorDisk.vue' |
| | | export { MonitorMem, MonitorDisk } |
对比新文件 |
| | |
| | | <template> |
| | | <ContentWrap> |
| | | <el-tabs v-model="activeName"> |
| | | <el-tab-pane label="内存监控日志" name="monitorMem"> |
| | | <monitor-mem ref="memInfoRef" /> |
| | | </el-tab-pane> |
| | | <el-tab-pane label="硬盘监控日志" name="colum"> |
| | | <monitor-disk ref="diskInfoRef" /> |
| | | </el-tab-pane> |
| | | </el-tabs> |
| | | </ContentWrap> |
| | | </template> |
| | | <script lang="ts" setup> |
| | | import { MonitorMem, MonitorDisk } from './components' |
| | | |
| | | defineOptions({ name: 'InfraMonitor' }) |
| | | |
| | | const activeName = ref('monitorMem') // Tag 激活的窗口 |
| | | |
| | | </script> |
| | |
| | | <el-descriptions-item label="浏览器"> |
| | | {{ detailData.userAgent }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="登陆结果"> |
| | | <el-descriptions-item label="登录结果"> |
| | | <dict-tag :type="DICT_TYPE.SYSTEM_LOGIN_RESULT" :value="detailData.result" /> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="登录日期"> |