需求描述:
鼠标悬浮在表格的IP字段上时,使用tooltip展示IP信息,如图:
1.封装根据IP展示信息的组件
请求接口获取IP信息,注意请求接口时防抖
<!-- 根据IP展示资产信息 -->
<template>
<div>
<el-tooltip placement="left" trigger="hover" :show-after="500">
<template #content>
<div v-if="state.ipAssetLoading">loading</div>
<div v-else>
<!-- IP信息 -->
<div>
<div class="font-bold">{{ t('alertQuery.ipInfo') }}:</div>
<div>{{ t('alertQuery.ipInfo_ip') }}: {{ state.showIp }}</div>
<div>{{ t('alertQuery.ipInfo_address') }}: {{ state.showAssetInfo.ipAddressInfo }}</div>
</div>
<!-- 资产信息 -->
<template v-if="!_.isEmpty(state.showAssetInfo.ipAssetInfo)">
<el-divider></el-divider>
<div class="font-bold">{{ t('alertQuery.assetInfo') }}:</div>
<div v-for="item of state.showAssetInfo.ipAssetInfo" :key="item.key">
<div>{{ item.label }}: {{ item.value }}</div>
</div>
</template>
</div>
</template>
<el-link type="primary" @mouseenter="initIpAsset(state.ipValue)" :underline="false">
{{ state.ipValue }}
</el-link>
</el-tooltip>
</div>
</template>
<script setup lang="ts">
import _ from '@lodash';
import { initIpInfoLink } from '@/utils/util';
import { getIpInfo } from '@/api/common';
import type { AssetInfo } from '@/api/common';
const { t } = useI18n();
const state = reactive({
ipAssetLoading: false,
showAssetInfo: {} as AssetInfo,
ipValue: '',
showIp: '',
});
const props = defineProps<{ rowValue: string }>();
watch(
() => props.rowValue,
() => {
state.ipValue = props.rowValue;
},
{ immediate: true },
);
// 获取IP地址及资产信息
const searchInfoDebounce = _.debounce((_ip) => getIpAsset(_ip), 500);
// 获取IP
async function initIpAsset(ip: string) {
state.showIp = await initIpInfoLink(ip);
searchInfoDebounce(state.showIp);
}
async function getIpAsset(ip: string) {
try {
state.ipAssetLoading = true;
const res = await getIpInfo(ip);
if (res?.code) throw new Error(res?.message);
state.showAssetInfo.ipAddressInfo = res?.data?.ipAddressInfo ?? '';
state.showAssetInfo.ipAssetInfo = res?.data?.ipAssetInfo ?? [];
} catch (error) {
if (error === 'cancel' || error?.code === RESPONSE_CODE.CANCEL) return;
console.log(`[log] - getIpInfo - error:`, error);
} finally {
state.ipAssetLoading = false;
}
}
</script>
获取IP信息的方法
// 获取IP
export async function initIpInfoLink(ip: string) {
if (!ip) return '';
ip = _.escape(ip);
let _ip = ip;
// 兼容特殊的这种写法 192.168.2.101(192.168.2.101)
if (_ip.includes('(')) {
_ip = _ip.substr(0, _ip.indexOf('('));
}
// IP:端口格式
if (_ip.includes(':')) {
_ip = _ip.substr(0, _ip.indexOf(':'));
}
return _ip;
}
2.请求接口的文件
为了防止接口重复请求时请求被中断,在请求接口的时候加上时间Date.now()
// 通用接口
import type { ResDto } from '@/utils/request';
// 根据IP查询资产信息
export interface AssetInfo {
ipAssetInfo: { label: string; value: string; key: string }[];
ipAddressInfo: string;
}
export function getIpInfo(ip: string): ResDto<AssetInfo> {
return SecRequest({
method: 'POST',
url: '/test/alert/ip?time=' + Date.now(),
data: { ip },
});
}
3.在表格列中调用方法
首先判断表格的字段是否符合IP格式,符合再去调用封装好的组件
<el-table-column
v-for="col of appState.headList"
:key="col.value"
:label="col.label"
:prop="col.value"
align="center">
<template #default="scope">
<!--添加ip悬浮查看信息 -->
<template v-if="isFieldIP(scope.row[col?.value])">
<ShowIpAsset :rowValue="scope.row[col?.value] ?? ''"></ShowIpAsset>
</template>
</template>
</el-table-column>
// 导入组件
import ShowIpAsset from '@/components/VIpAsset/ShowIpAsset.vue';
// 判断字段内容是否符合IP格式
import { isFieldIP } from '@/utils/validate';
判断是否为IP字段
// 判断是否为IP字段
export function isFieldIP(ip: string) {
ip = _.escape(ip);
let _ip = ip;
if (_ip?.includes(':')) {
_ip = _ip.substr(0, _ip.indexOf(':'));
}
const reg =
/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/;
return reg.test(_ip);
}