Files
profitManage1.2/src/views/resource/serverRegister/index.vue
T
康冉冉 ac163a126a 优化批量流量图形展示页面Echarts图表X轴数据缩进逻辑,提升展示效果、单页面多路由缓存问题
1、优化批量流量图形展示页面Echarts图表X轴数据缩进逻辑,提升展示效果
2、添加代码注释,移除冗余代码,优化代码体积与执行效率
3、优化自定义日期时间区间组件,完善功能与视觉表现
4、优化路由匹配逻辑,解决单页面适配多路由场景下的 keep-alive 缓存错乱问题
2026-03-16 18:06:58 +08:00

1072 lines
53 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="app-container">
<el-tabs v-model="activeName" @tab-click="handleClick('noRequest')">
<el-tab-pane label="正常设备" name="first"></el-tab-pane>
<el-tab-pane label="下架设备" name="second"></el-tab-pane>
</el-tabs>
<div class="pageTopForm">
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" size="small" label-width="auto">
<el-col :span="6">
<el-form-item label="搜索" title="搜索" prop="queryParam">
<el-input
v-model="queryParams.queryParam"
placeholder="请输入公网IP/私网IP/设备SN/clientID"
clearable
@keyup.enter.native="handleQuery"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="在线状态" title="在线状态" prop="onlineStatus">
<el-select
v-model="queryParams.onlineStatus"
placeholder="请选择在线状态"
clearable>
<el-option
v-for="dict in dict.type.rm_register_online_state"
:key="dict.value"
:label="dict.label"
:value="dict.value"/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="多公网IP状态" title="多公网IP状态" prop="multiPublicIpStatus">
<el-select
v-model="queryParams.multiPublicIpStatus"
placeholder="请选择多公网IP状态"
clearable>
<el-option
v-for="dict in dict.type.rm_moreip_status"
:key="dict.value"
:label="dict.label"
:value="dict.value"/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="注册状态" title="注册状态" prop="registrationStatus">
<el-select
v-model="queryParams.registrationStatus"
placeholder="请选择注册状态"
clearable>
<el-option
v-for="dict in dict.type.rm_register_status"
:key="dict.value"
:label="dict.label"
:value="dict.value"/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="业务名称" title="业务名称" prop="businessName">
<el-select
v-model="queryParams.businessName"
placeholder="请选择业务名称"
clearable>
<el-option
v-for="item in busNameList"
:key="item.value"
:label="item.label"
:value="item.value"/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="逻辑节点标识" title="逻辑节点标识" prop="logicalNodeId">
<el-select
v-model="queryParams.logicalNodeId"
placeholder="请选择逻辑节点标识"
clearable>
<el-option
v-for="item in logicalNodeList"
:key="item.value"
:label="item.label"
:value="item.value"/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item class="lastBtnSty">
<el-button type="primary" size="mini" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-col>
</el-form>
<!-- 表格数据 -->
<TableList ref="tabRef" :columns="columns" :config="config" :modelIdent="this.$options.name" :queryParams="queryParams" :tableList="roleList" @fnClick="callback" @fnRenderList="handleClick" @value-change="handleValueChange">
<template #tempCopy="{ row, column}">
<span class="disInlineBlock" :style="`max-width: calc(100% - 19px);overflow: hidden;white-space: nowrap;text-overflow: ellipsis;vertical-align: middle;`">{{row.clientId}}</span>
<el-link :underline="false" icon="el-icon-document-copy" title="复制" v-clipboard:copy="row.clientId" v-clipboard:success="clipboardSuccess" style="margin-left: 5px;color: #409EFF;"></el-link>
</template>
<template #tempOutbound="{ row, column}">
{{row.outboundRate}}<span v-if="row && row.outboundRate">%</span>
</template>
<!-- 多公网IP状态 -->
<template #tempMultipubStatus="{ row, column }">
<dict-tag :options="dict.type.rm_moreip_status" :value="row.multiPublicIpStatus"/>
</template>
<!-- 注册状态 -->
<template #tempStatus="{ row, column }">
<dict-tag :options="dict.type.rm_register_status" :value="row.registrationStatus"/>
</template>
<!-- 在线状态 -->
<template #tempOnlineStatus="{ row, column }">
<dict-tag :options="dict.type.rm_register_online_state" :value="row.onlineStatus"/>
</template>
<!-- 标签 -->
<template #tempRemark="{ row, column }">
<template v-if="row.remark">
<el-tag v-for="(item, index) of row.remark.split(',')" :style="{marginLeft: index !== 0 ? '5px' : null}">
{{item}}<span v-if="index+1 !== row.remark.split(',').length" style="color: transparent;">,</span>
</el-tag>
</template>
</template>
<template #tempHandle="{ row, column }">
<div style="width: 96%;">
<!-- 非编辑状态显示文本 -->
<template v-if="!row.editStatus">
<span>{{ row.reportedBandwidth || '-'}}</span>
<el-button icon="el-icon-edit" style="padding: 0px;" type="text" @click="rowDataChange(row, true)"></el-button>
</template>
<template v-else>
<!-- 编辑状态显示输入框 -->
<el-col :style="`width: calc(100% - 30px)`">
<el-input
v-model="row.reportedBandwidth"
size="mini"
class="customSty"
@keyup.enter.native="$event.target.blur"
@blur="handleSubmit(row)"
></el-input>
</el-col>
<el-col style="width: 30px;font-size: 12px;vertical-align: middle;margin-left: 3px;line-height: 100%;">
<el-button size="mini" style="padding: 0px 0px;display: block;" type="text" @click="handleSubmit(row)">确定</el-button>
<el-button size="mini" style="padding: 0px 0px;margin-left: 0px!important;color: #616266;" type="text" @click="rowDataChange(row, false)">取消</el-button>
</el-col>
</template>
</div>
</template>
</TableList>
<!-- 查看执行结果弹窗 -->
<el-dialog title="命令执行结果" :visible.sync="open" width="800px" height="300px" append-to-body>
<div class="block" style="max-height: calc(100vh - 125px);overflow: auto;">
<template v-if="timelineList && timelineList.length > 0">
<el-timeline :reverse="false">
<el-timeline-item v-for="item of timelineList" :timestamp="item.createTime" placement="top">
<pre>{{item.content}}</pre>
</el-timeline-item>
</el-timeline>
</template>
<el-empty v-else :image-size="200"></el-empty>
</div>
</el-dialog>
<!-- 下发业务 -->
<el-dialog :title="title" :visible.sync="issueOpen" width="800px" append-to-body style="padding-bottom: 20px;">
<BusinessIssuedDetails :open="`type_${issueOpen}`" :dialogRowData="dialogRowData" @dialogResult="fnDialogResult"></BusinessIssuedDetails>
</el-dialog>
<!-- 下发脚本策略 -->
<el-dialog :title="title" :visible.sync="scriptOpen" width="800px" append-to-body style="padding-bottom: 20px;">
<severScriptStratDetails :open="`type_${scriptOpen}`" :dialogRowData="dialogRowData" @dialogResult="fnDialogResult"></severScriptStratDetails>
</el-dialog>
<!-- 添加监控策略 -->
<el-dialog title="添加监控策略" :visible.sync="stratOpen" width="1200px" append-to-body>
<MonitorStrategy :open="`type_${stratOpen}`" :dialogRowData="dialogRowData" @dialogResult="fnDialogResult"></MonitorStrategy>
</el-dialog>
<!-- mtr探测丢包率趋势图 -->
<el-dialog title="MTR探测丢包率趋势图" :visible.sync="mtrChartOpen" width="1200px" append-to-body>
<lossRateChart :open="`type_${mtrChartOpen}`" :dialogRowData="dialogRowData" @dialogResult="fnDialogResult"></lossRateChart>
</el-dialog>
<!-- 选择公网业务IP -->
<el-dialog title="选择公网业务IP" :visible.sync="pubilcNetOpen" width="800px" append-to-body style="padding-bottom: 20px;">
<Form ref="publicNetFormRef" :formList="pubilcNetFormList" :ruleFormData="pubilcNetRuleForm" :config="{labelWidth: '140px', buttonGroup: []}" @fnClick="callback"></Form>
<div style="text-align: right;margin-right: 20px;margin-bottom: 20px;">
<el-button type="primary" style="margin-left: 10px;" @click="submitPubilc">提交</el-button>
<el-button @click="callback({fnCode: 'cancel'})">取消</el-button>
</div>
</el-dialog>
<!-- 标签 -->
<el-dialog :title="tagTitle" :visible.sync="tagOpen" width="800px" append-to-body style="padding-bottom: 20px;">
<div v-if="!(tagRuleForm && tagRuleForm.id)" style="margin-left: 20px; margin-bottom: 10px; color: #989898; font-size: 12px;">此页面只会对所选服务器增加标签不能查看和删除服务器原有的标签</div>
<Form ref="tagFormRef" :formList="tagFormList" :ruleFormData="tagRuleForm" :config="{labelWidth: '140px', buttonGroup: []}" @fnClick="callback"></Form>
<div style="text-align: right;margin-right: 20px;margin-bottom: 20px;">
<el-button type="primary" style="margin-left: 10px;" @click="submitTag">提交</el-button>
<el-button @click="callback({fnCode: 'cancel'})">取消</el-button>
</div>
</el-dialog>
<!-- 显示frp地址 -->
<el-dialog title="FRP连接地址" :visible.sync="frpOpen" width="800px" append-to-body style="padding-bottom: 20px;">
<div v-if="frpDialogContent.frpStatus == 1" class="textAlignCenter" style="font-size: 1rem;">
地址正在生成中......
</div>
<div v-else class="textAlignCenter" style="font-size: 1rem;">
地址:【{{frpDialogContent.frpcServerAddr}}端口:【{{frpDialogContent.port}}
<el-link :underline="false" icon="el-icon-document-copy" title="复制" v-clipboard:copy="frpDialogContent.collect" v-clipboard:success="clipboardSuccess" style="margin-left: 10px;color: #409EFF;"></el-link>
</div>
<div style="text-align: right;margin-right: 20px;margin-bottom: 20px;">
<el-button @click="callback({fnCode: 'cancel'})">取消</el-button>
</div>
</el-dialog>
<!-- 复制属性选择弹窗 -->
<el-dialog title="选择需要复制的属性" :visible.sync="copyDialogVisible" width="900px">
<div class="plr-50 pt20">
<el-checkbox-group v-model="selectedFields">
<el-checkbox style="width: 25%;margin-right: 0;" v-for="(field, key, index) of columns" :key="key" :label="key">
{{ field.label }}
</el-checkbox>
</el-checkbox-group>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="copyDialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirmCopy">确定</el-button>
</div>
</el-dialog>
</div>
</div>
</template>
<script setup name="Register">
import Form from '@/components/form/index.vue';
import {listHandle, networkList, getScriptResultBySn, getLogicalNode, addRemark, updateRemark, repBandwidthSubmit, bindBusPublic, getAlarmFlag,
virNetInterfaceChild, removeAlarmFlag, frpConnectLink, listFrpcConfig, removeServer, getLossList, agentIsNew, updateAgentManage} from '@/api/disRevenue/resource';
import {listAllBusinessList} from "@/api/disRevenue/earnManage"
import TableList from '@/components/table/index.vue';
import MonitorStrategy from '../serverMonitorStrat/monitorStrategy';
import severScriptStratDetails from '../serverScriptStrat/details';
import BusinessIssuedDetails from '../../earnManage/businessIssued/details';
import lossRateChart from '../mtrAgent/lossRateChart';
export default {
name: 'ServerRegister',
components: {TableList, MonitorStrategy,Form, BusinessIssuedDetails, severScriptStratDetails, lossRateChart},
dicts: ['rm_moreip_status', 'rm_register_status', 'rm_register_online_state', 'policy_method'],
data() {
return {
activeName: 'first',
cacheActiveName: 'first',
open: false,
stratOpen: false,
roleList: [],
busNameList: [],
loading: false,
showSearch: true,
ids: [],
single: true,
meltiple: true,
// 列显隐信息
columns: {
id: { label: `ID`,width: '45'},
clientId: { label: `clientID`, minWidth: '270', slotName: 'tempCopy',visible: true, disabled: true},
ip1Isp: { label: `运营商1`, minWidth: '55',visible: true, disabled: true},
ip1Province: { label: `省1`, minWidth: '50',visible: true, disabled: true},
ip1PublicIp:{ label: `IP1`,minWidth: '100',visible: true, disabled: true},
businessName: { label: `业务名称`, minWidth: '90', visible: true, disabled: true},
bandwidthResult: { label: `昨日95值`, minWidth: '75', visible: true, disabled: true, sortable: 'custom', ascending: 1, descending: 2},
bandwidthRate: { label: `日95利用率`, minWidth: '90', visible: true, disabled: true, sortable: 'custom', ascending: 5, descending: 6},
reportedBandwidth: { label: `上报带宽值`, minWidth: '70', slotName: 'tempHandle', visible: true, disabled: true},
outboundRate: { label: `出省流量占比`, minWidth: '90', slotName: 'tempOutbound', visible: true, disabled: true},
onlineStatus: { label: `在线状态`, slotName: 'tempOnlineStatus', minWidth: '60', visible: true, disabled: true},
hardwareSn: { label: `设备SN`,minWidth: '120'},
ip1City: { label: `市1`, minWidth: '50'},
ip1InterfaceName: { label: `接口名称1`, minWidth: '70'},
ip1MacAddress: { label: `mac地址1`, minWidth: '120'},
ip1InterfaceType: { label: `接口类型1`, minWidth: '70'},
ip1Ipv4Address: { label: `IPv4地址1`, minWidth: '110'},
ip1Gateway: { label: `网关1`, minWidth: '100'},
ip1Ipv6Address: { label: `IPv6全球单播地址1`, minWidth: '120'},
ip2Isp: { label: `运营商2`, minWidth: '55'},
ip2Province: { label: `省2`,minWidth: '50'},
ip2City: { label: `市2`, minWidth: '50'},
ip2PublicIp:{ label: `IP2`,minWidth: '100'},
ip2InterfaceName: { label: `接口名称2`, minWidth: '70'},
ip2MacAddress: { label: `mac地址2`, minWidth: '120'},
ip2InterfaceType: { label: `接口类型2`, minWidth: '70'},
ip2Ipv4Address: { label: `IPv4地址2`, minWidth: '110'},
ip2Gateway: { label: `网关2`, minWidth: '100'},
ip2Ipv6Address: { label: `IPv6全球单播地址2`, minWidth: '120'},
ip3Isp: { label: `运营商3`, minWidth: '55'},
ip3Province: { label: `省3`, minWidth: '50'},
ip3City: { label: `市3`, minWidth: '50'},
ip3PublicIp:{ label: `IP3`,minWidth: '100'},
ip3InterfaceName: { label: `接口名称3`, minWidth: '70'},
ip3MacAddress: { label: `mac地址3`, minWidth: '120'},
ip3InterfaceType: { label: `接口类型3`, minWidth: '70'},
ip3Ipv4Address: { label: `IPv4地址3`, minWidth: '110'},
ip3Gateway: { label: `网关3`, minWidth: '100'},
ip3Ipv6Address: { label: `IPv6全球单播地址3`, minWidth: '120'},
mgmtIsp: { label: `管理网-运营商`, minWidth: '95'},
mgmtProvince: { label: `管理网-省`,minWidth: '65'},
mgmtCity: { label: `管理网-市`, minWidth: '65'},
mgmtPublicIp:{ label: `管理网-IP`,minWidth: '120'},
mgmtInterfaceName: { label: `管理网-接口名称`, minWidth: '110'},
mgmtMacAddress: { label: `管理网-mac地址`, minWidth: '120'},
mgmtInterfaceType: { label: `管理网-接口类型`, minWidth: '110'},
mgmtIpv4Address: { label: `管理网-IPv4地址`, minWidth: '120'},
mgmtGateway: { label: `管理网-网关`, minWidth: '90'},
mgmtIpv6Address: { label: `管理网-IPv6全球单播地址`, minWidth: '160'},
remark: { label: `标签`, minWidth: '150', slotName: 'tempRemark'},
heartbeatInterval: { label: `心跳时间间隔`, minWidth: '90'},
heartbeatCount: { label: `心跳次数`, minWidth: '60'},
registrationStatus: { label: `注册状态`, slotName: 'tempStatus', minWidth: '60', visible: true},
logicalNodeId: { label: `逻辑节点标识`, minWidth: '90', visible: true},
multiPublicIpStatus: { label: `多公网IP状态`, slotName: 'tempMultipubStatus', minWidth: '90', visible: true },
createTime:{ label: `注册时间`,minWidth: '90'},
onboardTime:{ label: `上机时间`,minWidth: '90'},
agentVersion:{ label: `agent版本`,minWidth: '80'},
machineCode:{ label: `金山machineCode`,minWidth: '120'},
cpuUtil:{ label: `CPU使用率`,minWidth: '80'},
memUtil:{ label: `内存使用率`,minWidth: '80'},
},
config: {},
firstConfig: {
tableButton: {
top: [
{content: '添加金山machineCode', fnCode: 'add', type: 'primary', icon: 'el-icon-plus', hasPermi: 'resource:serverRegister:add'},
{content: '修改业务名称', fnCode: 'edit', type: 'success', icon: 'el-icon-edit', hasPermi: 'resource:serverRegister:edit'},
{content: '批量增加标签', fnCode: 'tagRemark', type: 'primary', icon: 'el-icon-plus', hasPermi: 'resource:serverRegister:tagRemark'},
{content: '流量图形展示', fnCode: 'trafficChart', type: 'primary', icon: 'el-icon-data-analysis', hasPermi: 'resource:serverRegister:trafficChart'},
{content: '导出', fnCode: 'export', type: 'warning', icon: 'el-icon-download', hasPermi: 'resource:serverRegister:export'},
{content: '下架', fnCode: 'unShelve', type: 'danger', icon: 'el-icon-bottom', hasPermi: 'resource:serverRegister:unShelve'},
{content: '批量更新agent', fnCode: 'updateAgent', type: 'primary', icon: 'el-icon-refresh-right', hasPermi: 'resource:serverRegister:updateAgent'},
{content: '批量复制', fnCode: 'copyList', type: 'primary', icon: 'el-icon-copy-document', hasPermi: 'resource:serverRegister:copyList'},
],
line: [
{content: '选择业务IP', fnCode: 'pubilcNet', type: 'primary', icon: 'el-icon-thumb', showName: 'multiPublicIpStatus', showVal: '0', hasPermi: 'resource:serverRegister:pubilcNet'},
// {content: '图形监控', fnCode: 'echartView', type: 'primary', icon: 'el-icon-data-analysis', hasPermi: 'resource:serverRegister:echartView'},// rocketmq:traffic
{content: '详情', fnCode: 'details', type: 'primary', icon: 'el-icon-view', hasPermi: 'rocketmq:traffic'}, // resource:serverRegister:details
{title: '更多', hasPermi: ['system:businessDeploy', 'rocketmq:policy', 'rocketmq:monitorPolicy', 'rocketmq:remote', 'resource:serverRegister:tagRemarkEdit', 'resource:serverRegister:mtrChartVew', 'resource:serverRegister:cancelFlash', 'resource:serverRegister:createFrpAddr', 'resource:serverRegister:showFrpAddr'], more: [
{content: '下发业务', fnCode: 'issueBusiness', type: 'text', icon: 'el-icon-circle-check', hasPermi: 'system:businessDeploy'},
{content: '下发脚本策略', fnCode: 'issueScript', type: 'text', icon: 'el-icon-circle-check', hasPermi: 'rocketmq:policy'},
{content: '下发监控策略', fnCode: 'issueMonitor', type: 'text', icon: 'el-icon-circle-check', hasPermi: 'rocketmq:monitorPolicy'},
{content: '查看执行结果', fnCode: 'result', type: 'text', icon: 'el-icon-s-check', hasPermi: 'rocketmq:remote'},
{content: '修改标签', fnCode: 'tagRemark', type: 'text', icon: 'el-icon-edit', hasPermi: 'resource:serverRegister:tagRemarkEdit'},
{content: 'MTR探测丢包率趋势图', fnCode: 'mtrChartVew', type: 'text', icon: 'el-icon-data-analysis', hasPermi: 'resource:serverRegister:mtrChartVew'},
{content: '取消闪烁', fnCode: 'cancelFlash', type: 'text', showName: 'alarmFlag', showVal: 'true', icon: 'el-icon-magic-stick', hasPermi: 'resource:serverRegister:cancelFlash'},
{content: '生成FRP连接地址', fnCode: 'createFrpAddr', type: 'text', showName: 'frpcConnectionStatus', showVal: ['0', null], icon: 'el-icon-link', hasPermi: 'resource:serverRegister:createFrpAddr'},
{content: '显示FRP连接地址', fnCode: 'showFrpAddr', type: 'text', showName: 'frpcConnectionStatus', showVal: ['1','2'], icon: 'el-icon-link', hasPermi: 'resource:serverRegister:showFrpAddr'},
{content: 'PPPoE配置', fnCode: 'poeConfig', type: 'text', icon: 'el-icon-data-analysis', hasPermi: 'resource:serverRegister:poeConfig'},
]
}
]
}
},
secondConfig: {
tableButton: {
line: [
{content: '详情', fnCode: 'details', type: 'primary', icon: 'el-icon-view', hasPermi: 'rocketmq:traffic'}
]
}
},
queryParams: {
pageNum: 1,
pageSize: 10,
total: 0
},
timelineList: [],
issueOpen: false,
scriptOpen: false,
title: '',
formList: [],
ruleForm: {},
pubilcNetOpen: false,
pubilcNetFormList: [{
config: {title: '',labelWidth: '140px', colSpan: 'disBlock m0Auto'},
controls: {
id: {label: 'ID',hidden: true},
clientId: {label: 'ClientID',hidden: true},
publicIp: {label: '业务公网IP', span: 18, eventName:'change', type: 'select',multiple: true, multipleLimit: 3, options: [], required: true},
descriptionOne: {label: '', span: 18, type: 'textarea',rows: 15, style: 'line-height: 22px;', hidden: true, disabled: true},
mgmtIp: {label: '管理网-公网IP', eventName:'change', span: 18, type: 'select',options: [], required: true},
descriptionTwo: {label: '', span: 18, type: 'textarea', rows: 15, style: 'line-height: 22px', hidden: true, disabled: true}
}
}],
pubilcNetRuleForm: {publicIp: []},
ipContentList: {},
dialogRowData: {},
logicalNodeList: [],
tagTitle: '',
tagOpen: false,
tagFormList: [{
config: {title: '',labelWidth: '140px', colSpan: 'disBlock m0Auto'},
controls: {
id: {label: 'ID',hidden: true},
remark: {label: '标签', span: 18, type: 'dynamicTags'},
deployDevice: {label: '相关服务器', span: 18, type: 'textarea', rows: 10, required: true},
}
}],
tagRuleForm: {},
mtrChartOpen: false,
virNetInterList: {},
alarmFlagHight: false,
frpOpen: false,
frpDialogContent: {},
keepAliveFirst: false,
selectedFields: [],
selectedRows: [],
copyDialogVisible: false,
}
},
created() {
this.keepAliveFirst = true;
this.getHightLight();
this.fnBusNameList();
this.fnLogicalNode();
},
activated() {
this.$nextTick(() => {
if (!this.keepAliveFirst) {
this.getHightLight();
}
});
},
methods: {
handleClick(val) {
if (val && val === 'noRequest' && this.cacheActiveName === this.activeName) return;
if (this.cacheActiveName !== this.activeName) {
this.queryParams = {pageNum: 1, pageSize: 10, total: 0};
}
this.cacheActiveName = this.activeName;
this.$refs.tabRef.showSearch = true;
if (this.activeName === 'first') {
this.getHightLight();
} else if (this.activeName === 'second') {
this.fnGetLossList();
}
},
fnGetLossList() {
let params = JSON.parse(JSON.stringify(this.queryParams));
if (params && !params.queryParam) {
params.queryParam = null;
}
if (this.alarmFlagHight && !params.bandwidthResultSort) {
params = Object.assign({}, params, {bandwidthResultSort: 4});
}
// this.$modal.loading();
getLossList(this.addDateRange(params)).then(response => {
this.config = {...this.secondConfig};
this.roleList = response.rows;
delete this.queryParams.resetVal;
this.queryParams.total = response.total;
}).catch(() => {
this.config = {...this.secondConfig};
});
},
fnBusNameList() {
listAllBusinessList().then(val => {
this.busNameList = val && val.data.map(item => {
return Object.assign({label: item.businessName, value: item.businessName});
});
});
},
fnLogicalNode() {
getLogicalNode().then(val => {
this.logicalNodeList = val && val.map(item => {
return Object.assign({label: item.logicalNodeId, value: item.logicalNodeId});
});
});
},
// 处理子组件传递的新值
handleValueChange(newValue) {
// 父组件更新自身数据,实现同步
this.showSearch = newValue;
},
// 高亮数据查询
getHightLight() {
getAlarmFlag().then(res => {
if (res && res.data) {
this.alarmFlagHight = true;
} else {
this.alarmFlagHight = false;
}
this.getList();
}).catch(() => {
this.alarmFlagHight = false;
this.getList();
});
},
/** 查询角色列表 */
getList() {
let params = JSON.parse(JSON.stringify(this.queryParams));
if (params && !params.queryParam) {
params.queryParam = null;
}
if (this.alarmFlagHight && !params.bandwidthResultSort) {
params = Object.assign({}, params, {bandwidthResultSort: 4});
}
listHandle(this.addDateRange(params)).then(response => {
this.config = {...this.firstConfig};
this.roleList = response.rows;
delete this.queryParams.resetVal;
this.queryParams.total = response.total;
this.keepAliveFirst = false;
}).catch(() => {
this.keepAliveFirst = false;
this.config = {...this.firstConfig};
});
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.handleClick();
},
/** 重置按钮操作 */
resetQuery() {
this.$refs['queryRef'].resetFields();
this.queryParams = {pageNum: 1, pageSize: 10,total: 0, resetVal: true};
this.handleClick();
},
/** 多选框选中数据 */
handleSelectionChange(selection) {
this.ids = selection.map(item => item.roleId);
this.single = selection.length != 1;
this.multiple = !selection.length;
},
/** 复制代码成功 */
clipboardSuccess() {
this.$modal.msgSuccess("复制成功")
},
fnDialogResult(res){
this.stratOpen = false;
this.issueOpen = false;
this.scriptOpen = false;
this.mtrChartOpen = false;
},
// 是否进入可编辑状态
rowDataChange(row, bool) {
this.$set(row, 'editStatus', bool);
},
// 提交编辑值
handleSubmit(rowData) {
// 控制单点,防止多次点击
if (this.loading) return;
this.loading = true;
repBandwidthSubmit(rowData).then(response => {
this.$set(rowData, 'editStatus', false);
this.getHightLight();
this.$modal.msgSuccess(response.msg);
this.loading = false;
}).catch(() => {
this.$modal.msgError("操作失败");
this.loading = false;
});
},
/** 图形分析 */
// graphicTraffic(list) {
// // 生成唯一 key(避免数据冲突)
// const storageKey = `temp_data_${Date.now()}`;
// // 1. 将数据存入 localStorage(需序列化)
// localStorage.setItem(storageKey, JSON.stringify({clientIdList: list}));
// // 1. 用 Vue Router 解析目标路由的完整 URL
// const routeLocation = this.$router.resolve({
// name: 'TrafficChart',
// query: { storageKey }
// });
// // 2. 打开新窗口(routeLocation.href 是完整路径)
// window.open(routeLocation.href, '_blank');
// // _blank:新标签页;_self:当前窗口(默认)
// },
async fnVirtualContent(rowData, content, formValCol) {
let virtuaContent = '';
let newVirtuaContent = '';
rowData && rowData.forEach(item => {
let interfaceName = this.ipContentList[item].interfaceName;
virNetInterfaceChild({clientId: this.pubilcNetRuleForm.clientId, parentInterface: interfaceName}).then(res => {
res && res.data.forEach((val, index) => {
virtuaContent += '<div style="padding-left: 20px;">'
+ '运营商:' + val.isp + '<br>' + '省:' + val.province + '<br>'
+ '市:' + val.city + '<br>' + '公网IP' + val.publicIp + '<br>'
+ '接口名称:' + val.interfaceName + '<br>' + 'mac地址:' + val.macAddress + '<br>'
+ '接口类型:' + val.interfaceType + '<br>' + 'IPv4地址:' + val.ipv4Address + '<br>'
+ '网关:' + val.gateway + '<br>' + 'IPv6全球单播地址:' + val.ipv6Address + '</div>';
if (index + 1 !== res.data.length) {
virtuaContent+= '<br>';
}
});
this.virNetInterList[interfaceName] = {typeVal: true, content: virtuaContent};
if (res && res.data && res.data.length > 0) {
newVirtuaContent = '<div style="width: 50%; height: '+ rowData.length * 210 +'px;overflow: auto; display: inline-block; vertical-align: top;"><div style="color: #1890FF;">' + interfaceName + '的虚拟网卡信息:</div>'
newVirtuaContent += virtuaContent + '</div>';
}
this.$set(this.pubilcNetRuleForm, formValCol, content + newVirtuaContent);
}).catch(() => {
this.$set(this.pubilcNetRuleForm, formValCol, content);
});
});
},
// 确认复制
confirmCopy() {
// 校验是否选择了要复制的属性
if (this.selectedFields.length === 0) {
this.$message.warning('请选择需要复制的属性');
return
}
try {
// 拼接复制内容
let copyText = '';
this.selectedRows.forEach((row, index) => {
if (index !== 0) {
// 从第二行开始,每行开头添加换行
copyText += '\n'
}
// 拼接选中的属性
this.selectedFields.forEach(field => {
const fieldLabel = this.columns[Object.keys(this.columns).find(item => item === field)].label;
copyText += `${fieldLabel}${row[field]}`
});
});
// 复制到剪贴板
const textarea = document.createElement('textarea');
textarea.value = copyText;
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
// 提示成功
this.$message.success('复制成功!');
// 关闭弹窗
this.copyDialogVisible = false;
} catch (error) {
this.$message.error('复制失败,请手动复制');
console.error('复制失败:', error);
}
},
//agent版本是否为最新版本
fnAgentIsNew(model) {
return agentIsNew({agentVersion: model.maxAgentVersion}).then(res => {
return res && res.data;
});
},
async callback(result, rowData, selectChange, selectList) {
this.dialogRowData = {};
if (result && result.fnCode) {
switch (result.fnCode) {
case 'add':
this.$router.push("/resource/serverRegister/edit");
break;
case 'edit':
let clientIdList = '';
if (selectList && selectList.length > 0) {
selectList.map(item => {
clientIdList+=item.clientId + '\n';
});
}
this.$router.push({
path:'/resource/serverRegister/edit',
query: {id: rowData.id, type: 'edit', clientIdList: clientIdList}
});
break;
case 'details':
this.$router.push({
path:'/resource/serverRegister/details',
query: {id: rowData.id, readonly: true, clientId: rowData.clientId}
});
break;
case 'poeConfig':
this.$router.push({
path:'/resource/serverRegister/details',
query: {id: rowData.id, readonly: true, target: 'PPPoE配置', clientId: rowData.clientId}
});
break;
case 'echartView':
this.$router.push({
path:'/resource/serverRegister/monitorChart',
query: {clientId: rowData.clientId}
});
break;
case 'trafficChart':
if (selectList && selectList.length <= 0) {
this.$modal.msgWarning("请选择数据!");
return;
}
let clientIdData = {};
selectList.forEach(item => {
let interFaceList = [];
if (item && item.ip1InterfaceName) {
interFaceList.push(item.ip1InterfaceName);
}
if (item && item.ip2InterfaceName) {
interFaceList.push(item.ip2InterfaceName);
}
if (item && item.ip3InterfaceName) {
interFaceList.push(item.ip3InterfaceName);
}
clientIdData[item.clientId] = interFaceList;
});
this.$router.push({
path:'/resource/serverRegister/trafficChart',
query: {clientIdList: JSON.stringify(clientIdData)}
});
// 原打开新页面使用
// this.graphicTraffic(clientIdData);
break;
case 'mtrChartVew':
this.mtrChartOpen = true;
this.dialogRowData = rowData;
break;
case 'tagRemark':
this.tagRuleForm = {};
this.tagOpen = true;
this.$nextTick(() => {
// 5. 最后执行重置
if (this.$refs['tagFormRef']?.$refs.ruleForm) {
this.$refs['tagFormRef'].$refs.ruleForm.resetFields();
}
this.tagFormList[0].controls.deployDevice['disabled'] = false;
if (rowData && rowData.id) {
this.tagTitle = '修改标签';
this.$set(this.tagRuleForm, 'id', rowData.id);
this.$set(this.tagRuleForm, 'deployDevice', rowData.clientId);
this.$set(this.tagRuleForm, 'remark', rowData && rowData.remark ? rowData.remark.split(',') : null);
// this.tagRuleForm = this.deepCopy(modelVal);
this.tagFormList[0].controls.deployDevice['disabled'] = true;
} else {
this.tagTitle = '批量增加标签';
if (selectList && selectList.length > 0) {
let params = '';
selectList && selectList.forEach((item, index) => {
if (selectList.length === index + 1) {
params+= item.clientId;
} else {
params+= item.clientId + '\n'
}
});
this.$set(this.tagRuleForm, 'deployDevice', params);
this.$set(this.tagRuleForm, 'remark', null);
this.$set(this.tagRuleForm, 'id', null);
}
}
});
break;
case 'result':
this.timelineList = [];
// 获取详情
getScriptResultBySn({clientId: rowData.clientId}).then(val => {
this.open = true;
this.timelineList = val && val.data && val.data.scriptResult || [];
}).catch(() => {
this.open = true;
this.$modal.msgError("操作失败")
});
break;
case 'pubilcNet':
this.pubilcNetOpen = true;
this.virNetInterList = {};
this.pubilcNetRuleForm = {publicIp: [], mgmtIp: '', descriptionOne: '', descriptionTwo: ''};
this.$nextTick(() => {
this.pubilcNetFormList[0].controls.descriptionOne['hidden'] = true;
this.pubilcNetFormList[0].controls.descriptionTwo['hidden'] = true;
this.$set(this.pubilcNetRuleForm, 'id', rowData.id);
this.$set(this.pubilcNetRuleForm, 'clientId', rowData.clientId);
this.$set(this.pubilcNetRuleForm, 'descriptionOne', null);
this.$set(this.pubilcNetRuleForm, 'descriptionTwo', null);
// 5. 最后执行重置
if (this.$refs['publicNetFormRef']?.$refs.ruleForm) {
this.$refs['publicNetFormRef'].$refs.ruleForm.resetFields();
}
});
networkList({clientId: rowData.clientId, newFlag: 1}).then(res => {
let ipList = [];
res && res.data.map(item => {
this.ipContentList[item.id] = item;
ipList.push({label: item.interfaceName, value: item.id});
});
this.pubilcNetFormList[0].controls.publicIp['options'] = ipList;
this.pubilcNetFormList[0].controls.mgmtIp['options'] = ipList;
});
break;
case 'publicIp':
let content = '<div style="width: 50%;display: inline-block;">';
this.pubilcNetRuleForm = Object.assign({}, this.pubilcNetRuleForm, this.$refs.publicNetFormRef.$refs.ruleForm.model);
if (rowData && rowData.length > 0) {
this.pubilcNetFormList[0].controls.descriptionOne['hidden'] = false;
rowData.forEach((item,index) => {
if (index > 0) {
content+= '<br>';
}
content+= '运营商:' + this.ipContentList[item].isp + '<br>' + '省:' + this.ipContentList[item].province + '<br>'
+ '市:' + this.ipContentList[item].city + '<br>' + '公网IP' + this.ipContentList[item].publicIp + '<br>'
+ '接口名称:' + this.ipContentList[item].interfaceName + '<br>' + 'mac地址:' + this.ipContentList[item].macAddress + '<br>'
+ '接口类型:' + this.ipContentList[item].interfaceType + '<br>' + 'IPv4地址:' + this.ipContentList[item].ipv4Address + '<br>'
+ '网关:' + this.ipContentList[item].gateway + '<br>';
});
content+= '</div>';
} else {
this.pubilcNetFormList[0].controls.descriptionOne['hidden'] = true;
}
this.fnVirtualContent(rowData, content, 'descriptionOne');
break;
case 'mgmtIp':
let contentTow = '<div style="width: 50%;display: inline-block;">';
this.pubilcNetRuleForm = Object.assign({}, this.pubilcNetRuleForm, this.$refs.publicNetFormRef.$refs.ruleForm.model);
if (rowData) {
this.pubilcNetFormList[0].controls.descriptionTwo['hidden'] = false;
contentTow+= '运营商:' + this.ipContentList[rowData].isp + '<br>' + '省:' + this.ipContentList[rowData].province + '<br>'
+ '市:' + this.ipContentList[rowData].city + '<br>' + '公网IP' + this.ipContentList[rowData].publicIp + '<br>'
+ '接口名称:' + this.ipContentList[rowData].interfaceName + '<br>' + 'mac地址:' + this.ipContentList[rowData].macAddress + '<br>'
+ '接口类型:' + this.ipContentList[rowData].interfaceType + '<br>' + 'IPv4地址:' + this.ipContentList[rowData].ipv4Address + '<br>'
+ '网关:' + this.ipContentList[rowData].gateway + '<br>';
contentTow += '</div>';
} else {
this.pubilcNetFormList[0].controls.descriptionTwo['hidden'] = true;
}
this.fnVirtualContent([rowData], contentTow, 'descriptionTwo');
break;
case 'issueBusiness':
this.issueOpen = true;
this.title = '下发业务任务';
this.dialogRowData = rowData;
break;
case 'issueScript':
this.dialogRowData = rowData;
this.title = '添加脚本策略';
this.scriptOpen = true;
break;
case 'executionMethod':
if (rowData && rowData === '1') {
this.formList[0].controls.scheduledTime['hidden'] = false;
} else {
this.formList[0].controls.scheduledTime['hidden'] = true;
}
break;
case 'issueMonitor':
this.stratOpen = true;
this.dialogRowData = rowData;
break;
case 'sortTable':
if (rowData && rowData.sortType) {
let paramsNum = rowData.sortType;
if (rowData.sortType === 3) {
paramsNum = null;
}
this.queryParams['bandwidthResultSort'] = paramsNum;
this.getHightLight();
}
break;
case 'cancel':
this.issueOpen = false;
this.pubilcNetOpen = false;
this.tagOpen = false;
this.frpOpen = false;
break;
case 'cancelFlash':
removeAlarmFlag({id: rowData.id}).then(res => {
this.getHightLight();
});
break;
case 'createFrpAddr':
if (Number(rowData.onlineStatus) === 1 && rowData.agentVersion && this.compareVersions('1.1.8', rowData.agentVersion)) {
frpConnectLink({clientId: rowData.clientId}).then(res => {
this.$modal.msgSuccess(res.msg);
this.getHightLight();
});
} else {
this.$modal.confirm('agent版本大于等于1.1.8,并且服务器为在线状态,才可执行!', {submitTitle: '确定',hiddenCancel: true}).then(() => {
}).catch(() => {});
}
break;
case 'showFrpAddr':
this.frpDialogContent = {};
listFrpcConfig({clientId: rowData.clientId, pageNum: 1, pageSize: 10}).then(res => {
this.frpOpen = true;
if (res && res.rows && res.rows.length > 0) {
this.frpDialogContent = {
frpStatus: res.rows[0].frpcConnectionStatus,
frpcServerAddr: res.rows[0].frpcServerAddr,
port: res.rows[0].frpcRemotePort,
collect: res.rows[0].frpcServerAddr + ':' + res.rows[0].frpcRemotePort
};
}
}).catch(() => {
this.frpOpen = true;
});
break;
case 'unShelve':
if (selectList && selectList.length <= 0) {
this.$modal.msgWarning("请选择数据!");
return;
}
let unShelveContent = '<p style="font-size: 1rem;font-weight: 600;">下架</p>' +
'<p style="height: 0px;margin-bottom: 50px;">所选服务器下架后将不再服务器管理列表中展示!';
this.$modal.confirm(unShelveContent).then(() => {
removeServer({ids: selectChange}).then(response => {
this.$modal.msgSuccess(response.msg);
this.getHightLight();
});
}).catch(() => {});
break;
case 'updateAgent':
if (selectList && selectList.length <= 0) {
this.$message.warning('请选择数据!');
return;
}
if (selectList && selectList.length > 10) {
this.$message.warning('批量更新agent的最大限额为10条!');
return;
}
let clientIdStr = '';
selectList && selectList.forEach((item, index) => {
if (!this.compareVersions(item.maxAgentVersion, item.agentVersion)) {
if (selectList.length === index + 1) {
clientIdStr+= item.clientId;
} else {
clientIdStr+= item.clientId + '\n'
}
}
});
if (!clientIdStr) {
this.$modal.msgWarning("已是最新版本!");
return;
}
let agentType = await this.fnAgentIsNew(selectList[0]);
if (agentType && agentType.newFlag) {
let params = {deployDevice: clientIdStr, method: '0', fileUrl: agentType.fileUrl, fileMd5: agentType.fileMd5};
this.$modal.confirm('是否升级到最新?').then(() => {
updateAgentManage(params).then(res => {
this.getList();
this.$modal.msgSuccess("升级成功!");
});
}).catch(() => {});
} else {
this.$modal.msgWarning("已是最新版本!");
}
break;
case 'copyList':
if (selectList && selectList.length === 0) {
this.$message.warning('请先选择要复制的数据行!');
return;
}
this.selectedRows = selectList;
// 打开弹窗,默认清空之前选中的属性
this.selectedFields = ['clientId'];
this.copyDialogVisible = true;
break;
case 'export':
let paramsList = Object.assign({}, this.queryParams,rowData);
this.download("system/registration/export", paramsList, `服务器管理_${new Date().getTime()}.xlsx`, null, 'json');
break;
default:
}
}
},
// 判断版本是否相同
compareVersions(targetVer, version2) {
const v1 = targetVer.split('.').map(Number);
const v2 = version2.split('.').map(Number);
const maxLength = Math.max(v1.length, v2.length);
for (let i = 0; i < maxLength; i++) {
const num1 = v1[i] || 0;
const num2 = v2[i] || 0;
if (num1 !== num2) {
return num1 < num2;
}
}
return true; // 相等
},
// form验证
fnFormValid(val, model) {
return new Promise((resolve) => {
this.ruleFormData = {};
const formValid = this.$refs[`${val}`].$refs.ruleForm;
// 3. 操作form(如验证)
formValid.validate((valid) => {
if (valid) {
if (formValid.model?.deployDevice && Array.isArray(formValid.model.deployDevice)) {
formValid.model.deployDevice = formValid.model.deployDevice.join('/n');
}
this[`${model}`] = formValid.model;
resolve(true);
} else {
resolve(false);
}
});
});
},
async submit(){
if (!await this.fnFormValid('formRef', 'ruleFormData')) return;
let fnType = addMachine;
if (dataVal && dataVal.id) {
fnType = updateTopology;
}
if(this.loading) return;
this.loading = true;
fnType(dataVal).then(response => {
this.$modal.msgSuccess(response.msg);
this.issueOpen = false;
this.loading = false;
}).catch(() => {
this.$modal.msgError("操作失败")
});
},
async submitPubilc() {
if (!await this.fnFormValid('publicNetFormRef', 'pubilcNetRuleForm')) return;
let params = [];
this.pubilcNetRuleForm.publicIp.forEach(item => {
if (item && item === this.pubilcNetRuleForm.mgmtIp) {
params.push({id: item, status: 3, interfaceName: this.ipContentList[item].interfaceName});
delete this.pubilcNetRuleForm.mgmtIp;
} else {
params.push({id: item, status: 1, interfaceName: this.ipContentList[item].interfaceName});
}
});
if (this.pubilcNetRuleForm && this.pubilcNetRuleForm.mgmtIp) {
params.push({id: this.pubilcNetRuleForm.mgmtIp, status: 2, interfaceName: this.ipContentList[this.pubilcNetRuleForm.mgmtIp].interfaceName});
}
bindBusPublic({id: this.pubilcNetRuleForm.id, clientId: this.pubilcNetRuleForm.clientId, bindNetworkMsg: params}).then(res => {
this.$modal.msgSuccess(res.msg);
this.pubilcNetOpen = false;
this.getHightLight();
});
},
// 添加标签
async submitTag() {
if (!await this.fnFormValid('tagFormRef', 'tagRuleForm')) return;
let params = JSON.parse(JSON.stringify(this.tagRuleForm));
params['remark'] = params && params.remark && params.remark.length > 0 ? params.remark.join() : null;
let fnType = addRemark;
if (params && params.id) {
fnType = updateRemark;
}
fnType(params).then(res => {
this.$modal.msgSuccess(res.msg);
this.tagOpen = false;
this.tagRuleForm = {};
this.$refs.tabRef.defaultSelectRows([]);
this.getHightLight();
});
},
}
}
</script>
<style scoped>
::v-deep .lastBtnSty .el-form-item__content{
margin-left: 10px!important;
}
::v-deep .el-dialog__body {
padding: 0 0 10px!important;
}
::v-deep .el-timeline .el-timeline-item:last-child .el-timeline-item__tail {
display: block!important;
}
::v-deep .el-tree-node__label {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
::v-deep .customSty .el-input__inner {
padding: 0 2px 0!important;
}
::v-deep .el-table th.el-table__cell > .cell {
padding-left: 2px!important;
padding-right: 2px!important;
}
::v-deep .el-table .cell {
padding-left: 0px!important;
padding-right: 0px!important;
}
</style>