Merge remote-tracking branch 'origin/main' into multi-tenant
This commit is contained in:
@@ -707,6 +707,26 @@ export default {
|
||||
licenseTip2: '2. Clicking [Finish] will end the installation process.',
|
||||
},
|
||||
},
|
||||
neData: {
|
||||
baseStation: {
|
||||
list: "List",
|
||||
topology: "Topology",
|
||||
nbName: "Equipment Name",
|
||||
topologyTitle: "Radio State Graph",
|
||||
name: "Radio Name",
|
||||
namePlease: "text content length 0~64",
|
||||
position: "Radio Address",
|
||||
positionPlease: "location description. Prohibition of spaces, length of text content 0-64",
|
||||
address: "IP Address",
|
||||
addressPlease: "text content length 0~64",
|
||||
state: "Radio State",
|
||||
online: "Online",
|
||||
offline: "Offline",
|
||||
time: "Change Time",
|
||||
addRadio: "Add Radio Info",
|
||||
editRadio: "Edit Radio Info",
|
||||
},
|
||||
},
|
||||
neUser: {
|
||||
auth: {
|
||||
authInfo:' Authentication Info',
|
||||
@@ -965,10 +985,10 @@ export default {
|
||||
},
|
||||
kpiOverView:{
|
||||
"kpiName":"NE Metrics Name",
|
||||
"maxValue":"Max Value",
|
||||
"minValue":"Min Value",
|
||||
"avgValue":"Average Value",
|
||||
"totalValue":"Worth Value",
|
||||
"maxValue":"Max",
|
||||
"minValue":"Min",
|
||||
"avgValue":"Avg",
|
||||
"totalValue":"Total",
|
||||
"kpiChartTitle":"Overview of NE metrics",
|
||||
"changeLine":"Change to Line Charts",
|
||||
"changeBar":"Change to Bar Charts",
|
||||
|
||||
@@ -707,6 +707,26 @@ export default {
|
||||
licenseTip2: '2. 点击【结束】将结束安装过程',
|
||||
},
|
||||
},
|
||||
neData: {
|
||||
baseStation: {
|
||||
list: "列表",
|
||||
topology: "拓扑图",
|
||||
nbName: "设备名称",
|
||||
topologyTitle: "基站状态关系图",
|
||||
name: "基站名称",
|
||||
namePlease: "文本内容长度0~64",
|
||||
position: "基站位置",
|
||||
positionPlease: "位置描述。禁止空格,文本内容长度0-64",
|
||||
address: "IP地址",
|
||||
addressPlease: "文本内容长度0~64",
|
||||
state: "基站状态",
|
||||
online: "在线",
|
||||
offline: "离线",
|
||||
time: "变更时间",
|
||||
addRadio: "添加基站信息",
|
||||
editRadio: "更新基站信息",
|
||||
},
|
||||
},
|
||||
neUser: {
|
||||
auth: {
|
||||
authInfo:'鉴权信息',
|
||||
|
||||
@@ -20,13 +20,13 @@ const route = useRoute();
|
||||
const nbState = ref<DictType[]>([
|
||||
{
|
||||
value: 'ON',
|
||||
label: 'Online',
|
||||
label: t('views.neData.baseStation.online'),
|
||||
tagType: 'green',
|
||||
tagClass: '',
|
||||
},
|
||||
{
|
||||
value: 'OFF',
|
||||
label: 'Offline',
|
||||
label: t('views.neData.baseStation.offline'),
|
||||
tagType: 'red',
|
||||
tagClass: '',
|
||||
},
|
||||
@@ -75,48 +75,55 @@ let tableState: TabeStateType = reactive({
|
||||
/**表格字段列 */
|
||||
let tableColumns = ref<ColumnsType>([
|
||||
{
|
||||
title: 'Index',
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'index',
|
||||
align: 'left',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: 'Name',
|
||||
title: t('views.neData.baseStation.name'),
|
||||
dataIndex: 'name',
|
||||
align: 'left',
|
||||
width: 150,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: 'Position',
|
||||
title: t('views.neData.baseStation.position'),
|
||||
dataIndex: 'position',
|
||||
align: 'left',
|
||||
width: 150,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: 'Address',
|
||||
title: t('views.neData.baseStation.address'),
|
||||
dataIndex: 'address',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'State',
|
||||
title: t('views.neData.baseStation.nbName'),
|
||||
dataIndex: 'nbName',
|
||||
align: 'left',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: t('views.neData.baseStation.state'),
|
||||
dataIndex: 'state',
|
||||
key: 'state',
|
||||
align: 'left',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: 'Time',
|
||||
title: t('views.neData.baseStation.time'),
|
||||
align: 'left',
|
||||
width: 150,
|
||||
customRender(opt) {
|
||||
const record = opt.value;
|
||||
console.log(opt)
|
||||
if (record.state === 'OFF') {
|
||||
return record.offTime;
|
||||
return record.offTime || '-';
|
||||
}
|
||||
return record.onTime;
|
||||
return record.onTime || '-';
|
||||
},
|
||||
},
|
||||
]);
|
||||
@@ -277,13 +284,14 @@ let modalState: ModalStateType = reactive({
|
||||
const modalStateFrom = Form.useForm(
|
||||
modalState.from,
|
||||
reactive({
|
||||
address: [{ required: true, message: `text content length 0~64` }],
|
||||
name: [{ required: true, message: `text content length 0~64` }],
|
||||
address: [
|
||||
{ required: true, message: t('views.neData.baseStation.addressPlease') },
|
||||
],
|
||||
name: [
|
||||
{ required: true, message: t('views.neData.baseStation.namePlease') },
|
||||
],
|
||||
position: [
|
||||
{
|
||||
required: true,
|
||||
message: `location description. Prohibition of spaces, length of text content 0-64`,
|
||||
},
|
||||
{ required: true, message: t('views.neData.baseStation.positionPlease') },
|
||||
],
|
||||
})
|
||||
);
|
||||
@@ -295,7 +303,7 @@ const modalStateFrom = Form.useForm(
|
||||
function fnModalVisibleByEdit(edit?: string | number) {
|
||||
if (!edit) {
|
||||
modalStateFrom.resetFields(); //重置表单
|
||||
modalState.title = 'Add Radio Info';
|
||||
modalState.title = t('views.neData.baseStation.addRadio');
|
||||
modalState.openByEdit = true;
|
||||
// 获取最大index
|
||||
if (tableState.data.length <= 0) {
|
||||
@@ -312,7 +320,7 @@ function fnModalVisibleByEdit(edit?: string | number) {
|
||||
});
|
||||
modalStateFrom.resetFields(); //重置表单
|
||||
Object.assign(modalState.from, row);
|
||||
modalState.title = 'Edit Radio Info';
|
||||
modalState.title = t('views.neData.baseStation.editRadio');
|
||||
modalState.openByEdit = true;
|
||||
}
|
||||
}
|
||||
@@ -427,8 +435,11 @@ onMounted(() => {
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="6" :md="12" :xs="24">
|
||||
<a-form-item label="State" name="state">
|
||||
<a-col :lg="4" :md="6" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.neData.baseStation.state')"
|
||||
name="state"
|
||||
>
|
||||
<a-select
|
||||
v-model:value="queryParams.state"
|
||||
:options="nbState"
|
||||
@@ -546,7 +557,7 @@ onMounted(() => {
|
||||
:labelWrap="true"
|
||||
>
|
||||
<a-form-item
|
||||
label="Name"
|
||||
:label="t('views.neData.baseStation.name')"
|
||||
name="name"
|
||||
v-bind="modalStateFrom.validateInfos.name"
|
||||
>
|
||||
@@ -558,24 +569,24 @@ onMounted(() => {
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="Address"
|
||||
name="address"
|
||||
v-bind="modalStateFrom.validateInfos.address"
|
||||
:label="t('views.neData.baseStation.position')"
|
||||
name="position"
|
||||
v-bind="modalStateFrom.validateInfos.position"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="modalState.from.address"
|
||||
v-model:value="modalState.from.position"
|
||||
allow-clear
|
||||
:maxlength="64"
|
||||
>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="Position"
|
||||
name="position"
|
||||
v-bind="modalStateFrom.validateInfos.position"
|
||||
:label="t('views.neData.baseStation.address')"
|
||||
name="address"
|
||||
v-bind="modalStateFrom.validateInfos.address"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="modalState.from.position"
|
||||
v-model:value="modalState.from.address"
|
||||
allow-clear
|
||||
:maxlength="64"
|
||||
>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive, onMounted, ref, onBeforeUnmount, useTemplateRef } from 'vue';
|
||||
import { Graph, GraphData, Menu, Tooltip } from '@antv/g6';
|
||||
import { Graph, GraphData, Menu, Tooltip, Util } from '@antv/g6';
|
||||
import { listAMFNbStatelist } from '@/api/neData/amf';
|
||||
import { parseBasePath } from '@/plugins/file-static-url';
|
||||
import { edgeLineAnimateState } from '@/views/monitor/topologyBuild/hooks/registerEdge';
|
||||
@@ -80,6 +80,22 @@ const graphNodeMenu = new Menu({
|
||||
getContent(evt) {
|
||||
if (!evt) return t('views.monitor.topologyBuild.graphNotInfo');
|
||||
const { id, label, nType, nInfo }: any = evt.item?.getModel();
|
||||
if (['GNB', 'ENB'].includes(nType)) {
|
||||
return `
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 140px;
|
||||
"
|
||||
>
|
||||
<span>
|
||||
${t('views.neData.baseStation.name')}:
|
||||
${label ?? '--'}
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
return `
|
||||
<div
|
||||
style="
|
||||
@@ -110,29 +126,29 @@ const graphNodeTooltip = new Tooltip({
|
||||
style="
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 228px;
|
||||
width: 256px;
|
||||
"
|
||||
>
|
||||
<div><strong>${t('views.monitor.topology.state')}:</strong><span>
|
||||
<div><strong>${t('views.neData.baseStation.state')}:</strong><span>
|
||||
${
|
||||
nInfo.state === 'ON'
|
||||
? t('views.monitor.topology.normalcy')
|
||||
: t('views.monitor.topology.exceptions')
|
||||
? t('views.neData.baseStation.online')
|
||||
: t('views.neData.baseStation.offline')
|
||||
}
|
||||
</span></div>
|
||||
<div><strong>OnTime:</strong><span>
|
||||
${nInfo.onTime ?? '--'}
|
||||
<div><strong>${t('views.neData.baseStation.time')}:</strong><span>
|
||||
${nInfo.state === 'ON' ? nInfo.onTime ?? '--' : nInfo.offTime ?? '--'}
|
||||
</span></div>
|
||||
<div><strong>OffTime:</strong><span>
|
||||
${nInfo.offTime ?? '--'}
|
||||
</span></div>
|
||||
<div>===========================</div>
|
||||
<div>==============================</div>
|
||||
<div><strong>ID:</strong><span>${nInfo.index}</span></div>
|
||||
<div><strong>${t('views.monitor.topology.name')}:</strong><span>
|
||||
<div><strong>${t('views.neData.baseStation.address')}:</strong><span>
|
||||
${nInfo.address}</span></div>
|
||||
<div><strong>${t('views.neData.baseStation.name')}:</strong><span>
|
||||
${nInfo.name ?? '--'}
|
||||
</span></div>
|
||||
<div><strong>Address:</strong><span>${nInfo.address}</span></div>
|
||||
<div><strong>Position:</strong><span style="word-wrap: break-word;">
|
||||
<div><strong>${t(
|
||||
'views.neData.baseStation.position'
|
||||
)}:</strong><span style="word-wrap: break-word;">
|
||||
${nInfo.position}
|
||||
</span></div>
|
||||
</div>
|
||||
@@ -185,6 +201,33 @@ function registerEdgeNode() {
|
||||
nodeImageAnimateState();
|
||||
}
|
||||
|
||||
/**
|
||||
* format the string
|
||||
* @param {string} str The origin string
|
||||
* @param {number} maxWidth max width
|
||||
* @param {number} fontSize font size
|
||||
* @return {string} the processed result
|
||||
*/
|
||||
function fittingString(str: string, maxWidth: number, fontSize: number) {
|
||||
let currentWidth = 0;
|
||||
let res = str;
|
||||
const pattern = new RegExp('[\u4E00-\u9FA5]+'); // distinguish the Chinese charactors and letters
|
||||
str.split('').forEach((letter, i) => {
|
||||
if (currentWidth > maxWidth) return;
|
||||
if (pattern.test(letter)) {
|
||||
// Chinese charactors
|
||||
currentWidth += fontSize;
|
||||
} else {
|
||||
// get the width of single letter according to the fontSize
|
||||
currentWidth += Util.getLetterWidth(letter, fontSize);
|
||||
}
|
||||
if (currentWidth > maxWidth) {
|
||||
res = `${str.substring(0, i)}\n${str.substring(i)}`;
|
||||
}
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
/**图事件 */
|
||||
function graphEvent(graph: Graph) {
|
||||
graph.on('edge:mouseenter', evt => {
|
||||
@@ -236,8 +279,8 @@ function handleRanderGraph(container: HTMLElement | null, data: GraphData) {
|
||||
plugins: [graphNodeMenu, graphNodeTooltip],
|
||||
layout: {
|
||||
type: 'dagre',
|
||||
rankdir: 'BT', // 布局的方向,TB:从上到下,BT:从下到上,LR:从左到右,RL:从右到左
|
||||
align: 'UL', // 节点对齐方式 UL、UR、DL、DR
|
||||
rankdir: 'TB', // 布局的方向,TB:从上到下,BT:从下到上,LR:从左到右,RL:从右到左
|
||||
//align: 'UL', // 节点对齐方式 UL、UR、DL、DR
|
||||
controlPoints: true,
|
||||
nodesep: 20,
|
||||
ranksep: 40,
|
||||
@@ -344,7 +387,7 @@ async function fnGraphDataBase() {
|
||||
const node = {
|
||||
id: 'OMC',
|
||||
label: omcInfo.neName,
|
||||
img: parseBasePath('/svg/service.svg'),
|
||||
img: parseBasePath('/svg/service_db.svg'),
|
||||
nInfo: { online: false, neId: omcInfo.neId, neType: omcInfo.neType },
|
||||
nType: 'OMC',
|
||||
};
|
||||
@@ -393,7 +436,7 @@ async function fnGraphDataNb(data: GraphData) {
|
||||
const id = `${item.id}_${nb.index}`;
|
||||
data.nodes?.push({
|
||||
id: id,
|
||||
label: `${nb.name}`,
|
||||
label: fittingString(`${nb.name}`, 80, 14),
|
||||
img: parseBasePath('/svg/base5G.svg'),
|
||||
nInfo: nb,
|
||||
nType: 'GNB',
|
||||
@@ -531,7 +574,9 @@ onBeforeUnmount(() => {
|
||||
<a-card :bordered="false" :body-style="{ padding: '0' }" ref="viewportDom">
|
||||
<!-- 插槽-卡片左侧侧 -->
|
||||
<template #title>
|
||||
<a-space :size="8" align="center"> Radio State Graph </a-space>
|
||||
<a-space :size="8" align="center">
|
||||
{{ t('views.neData.baseStation.topologyTitle') }}
|
||||
</a-space>
|
||||
</template>
|
||||
<!-- 插槽-卡片右侧 -->
|
||||
<template #extra>
|
||||
@@ -540,7 +585,7 @@ onBeforeUnmount(() => {
|
||||
<FullscreenExitOutlined v-if="isFullscreen" />
|
||||
<FullscreenOutlined v-else />
|
||||
</template>
|
||||
Full Screen
|
||||
{{ t('loayouts.rightContent.fullscreen') }}
|
||||
</a-button>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -4,11 +4,16 @@ import {
|
||||
type Component,
|
||||
defineAsyncComponent,
|
||||
shallowRef,
|
||||
ref,
|
||||
} from 'vue';
|
||||
import { PageContainer } from 'antdv-pro-layout';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
const { t } = useI18n();
|
||||
const defineComponent = shallowRef<Component | null>(null);
|
||||
|
||||
function fnSwitch(name: string) {
|
||||
const value = ref<string>('list');
|
||||
function fnSwitch(evt: any) {
|
||||
const name = evt.target?.value;
|
||||
if (name === 'topology') {
|
||||
defineComponent.value = defineAsyncComponent(
|
||||
() => import('@/views/ne-data/base-station/components/topology.vue')
|
||||
@@ -22,15 +27,25 @@ function fnSwitch(name: string) {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fnSwitch('topology');
|
||||
fnSwitch({ target: { value: 'list' } });
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PageContainer>
|
||||
<template #extra>
|
||||
<a-button @click="fnSwitch('list')">List</a-button>
|
||||
<a-button type="primary" @click="fnSwitch('topology')">Topology</a-button>
|
||||
<a-radio-group
|
||||
v-model:value="value"
|
||||
button-style="solid"
|
||||
@change="fnSwitch"
|
||||
>
|
||||
<a-radio-button value="list">
|
||||
{{ t('views.neData.baseStation.list') }}
|
||||
</a-radio-button>
|
||||
<a-radio-button value="topology">
|
||||
{{ t('views.neData.baseStation.topology') }}
|
||||
</a-radio-button>
|
||||
</a-radio-group>
|
||||
</template>
|
||||
|
||||
<component :is="defineComponent" />
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
nextTick,
|
||||
onBeforeUnmount,
|
||||
h,
|
||||
watch
|
||||
watch,
|
||||
} from 'vue';
|
||||
import { PageContainer } from 'antdv-pro-layout';
|
||||
import { message, Modal, TableColumnType } from 'ant-design-vue/es';
|
||||
@@ -410,12 +410,13 @@ function fnGetList() {
|
||||
});
|
||||
|
||||
// 计算总值
|
||||
const total = Number(values.reduce((sum, val) => sum + val, 0).toFixed(2));
|
||||
const total = Number(
|
||||
values.reduce((sum, val) => sum + val, 0).toFixed(2)
|
||||
);
|
||||
|
||||
// 计算平均值
|
||||
const avg = values.length > 0
|
||||
? Number((total / values.length).toFixed(2))
|
||||
: 0;
|
||||
const avg =
|
||||
values.length > 0 ? Number((total / values.length).toFixed(2)) : 0;
|
||||
|
||||
kpiStats.value.push({
|
||||
kpiId: columns.key,
|
||||
@@ -423,7 +424,7 @@ function fnGetList() {
|
||||
max: values.length > 0 ? Math.max(...values) : 0,
|
||||
min: values.length > 0 ? Math.min(...values) : 0,
|
||||
avg: avg,
|
||||
total: total
|
||||
total: total,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -584,29 +585,31 @@ function fnRanderChartData() {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
axisLabel: {
|
||||
color: document.documentElement.getAttribute('data-theme') === 'dark'
|
||||
? '#CACADA'
|
||||
: '#333'
|
||||
color:
|
||||
document.documentElement.getAttribute('data-theme') === 'dark'
|
||||
? '#CACADA'
|
||||
: '#333',
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: getSplitLineColor()
|
||||
}
|
||||
color: getSplitLineColor(),
|
||||
},
|
||||
},
|
||||
data: chartDataXAxisData,
|
||||
},
|
||||
yAxis: {
|
||||
axisLabel: {
|
||||
color: document.documentElement.getAttribute('data-theme') === 'dark'
|
||||
? '#CACADA'
|
||||
: '#333'
|
||||
color:
|
||||
document.documentElement.getAttribute('data-theme') === 'dark'
|
||||
? '#CACADA'
|
||||
: '#333',
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: getSplitLineColor()
|
||||
}
|
||||
color: getSplitLineColor(),
|
||||
},
|
||||
},
|
||||
},
|
||||
series: chartDataYSeriesData,
|
||||
@@ -754,59 +757,49 @@ function getSplitLineColor() {
|
||||
// 监听主题变化
|
||||
watch(
|
||||
() => layoutStore.proConfig.theme, // 监听的值
|
||||
(newValue) => {
|
||||
newValue => {
|
||||
if (kpiChart.value) {
|
||||
const splitLineColor = getSplitLineColor();
|
||||
// 绘制图数据
|
||||
kpiChart.value.setOption(
|
||||
{
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
position: function (pt: any) {
|
||||
return [pt[0], '10%'];
|
||||
},
|
||||
confine: true, // 限制 tooltip 显示范围
|
||||
backgroundColor: newValue === 'dark'
|
||||
kpiChart.value.setOption({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
position: function (pt: any) {
|
||||
return [pt[0], '10%'];
|
||||
},
|
||||
confine: true, // 限制 tooltip 显示范围
|
||||
backgroundColor:
|
||||
newValue === 'dark'
|
||||
? 'rgba(48, 48, 48, 0.8)'
|
||||
: 'rgba(255, 255, 255, 0.9)',
|
||||
borderColor: newValue === 'dark'
|
||||
? '#555'
|
||||
: '#ddd',
|
||||
textStyle: {
|
||||
color: newValue === 'dark'
|
||||
? '#CACADA'
|
||||
: '#333'
|
||||
borderColor: newValue === 'dark' ? '#555' : '#ddd',
|
||||
textStyle: {
|
||||
color: newValue === 'dark' ? '#CACADA' : '#333',
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
axisLabel: {
|
||||
color: newValue === 'dark' ? '#CACADA' : '#333',
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: splitLineColor,
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
axisLabel: {
|
||||
color: newValue === 'dark'
|
||||
? '#CACADA'
|
||||
: '#333'
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: splitLineColor
|
||||
}
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
axisLabel: {
|
||||
color: newValue === 'dark' ? '#CACADA' : '#333',
|
||||
},
|
||||
yAxis: {
|
||||
axisLabel: {
|
||||
color: newValue === 'dark'
|
||||
? '#CACADA'
|
||||
: '#333'
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: splitLineColor,
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: splitLineColor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -878,39 +871,67 @@ onBeforeUnmount(() => {
|
||||
|
||||
<template>
|
||||
<PageContainer>
|
||||
<a-card v-show="tableState.seached" :bordered="false" :body-style="{ marginBottom: '24px', paddingBottom: 0 }">
|
||||
<a-card
|
||||
v-show="tableState.seached"
|
||||
:bordered="false"
|
||||
:body-style="{ marginBottom: '24px', paddingBottom: 0 }"
|
||||
>
|
||||
<!-- 表格搜索栏 -->
|
||||
<a-form :model="queryParams" name="queryParamsFrom" layout="horizontal">
|
||||
<a-row :gutter="16">
|
||||
<a-col :lg="6" :md="12" :xs="24">
|
||||
<a-form-item name="neType" :label="t('views.ne.common.neType')">
|
||||
<a-cascader v-model:value="state.neType" :options="neCascaderOptions" :allow-clear="false"
|
||||
:placeholder="t('common.selectPlease')" />
|
||||
<a-cascader
|
||||
v-model:value="state.neType"
|
||||
:options="neCascaderOptions"
|
||||
:allow-clear="false"
|
||||
:placeholder="t('common.selectPlease')"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="10" :md="12" :xs="24">
|
||||
<a-form-item :label="t('views.perfManage.goldTarget.timeFrame')" name="timeFrame">
|
||||
<a-range-picker v-model:value="queryRangePicker" bordered :allow-clear="false"
|
||||
:show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss" value-format="x"
|
||||
style="width: 100%"></a-range-picker>
|
||||
<a-form-item
|
||||
:label="t('views.perfManage.goldTarget.timeFrame')"
|
||||
name="timeFrame"
|
||||
>
|
||||
<a-range-picker
|
||||
v-model:value="queryRangePicker"
|
||||
bordered
|
||||
:allow-clear="false"
|
||||
:show-time="{ format: 'HH:mm:ss' }"
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
value-format="x"
|
||||
style="width: 100%"
|
||||
></a-range-picker>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="4" :md="12" :xs="24">
|
||||
<a-form-item :label="t('views.perfManage.goldTarget.interval')" name="interval">
|
||||
<a-select v-model:value="queryParams.interval" :placeholder="t('common.selectPlease')" :options="[
|
||||
{ label: '5S', value: 5 },
|
||||
{ label: '1M', value: 60 },
|
||||
{ label: '5M', value: 300 },
|
||||
{ label: '15M', value: 900 },
|
||||
{ label: '30M', value: 1800 },
|
||||
{ label: '60M', value: 3600 },
|
||||
]" />
|
||||
<a-form-item
|
||||
:label="t('views.perfManage.goldTarget.interval')"
|
||||
name="interval"
|
||||
>
|
||||
<a-select
|
||||
v-model:value="queryParams.interval"
|
||||
:placeholder="t('common.selectPlease')"
|
||||
:options="[
|
||||
{ label: '5S', value: 5 },
|
||||
{ label: '1M', value: 60 },
|
||||
{ label: '5M', value: 300 },
|
||||
{ label: '15M', value: 900 },
|
||||
{ label: '30M', value: 1800 },
|
||||
{ label: '60M', value: 3600 },
|
||||
]"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="2" :md="12" :xs="24">
|
||||
<a-form-item>
|
||||
<a-space :size="8">
|
||||
<a-button type="primary" :loading="tableState.loading" @click.prevent="fnGetListTitle()">
|
||||
<a-button
|
||||
type="primary"
|
||||
:loading="tableState.loading"
|
||||
@click.prevent="fnGetListTitle()"
|
||||
>
|
||||
<template #icon>
|
||||
<SearchOutlined />
|
||||
</template>
|
||||
@@ -927,7 +948,11 @@ onBeforeUnmount(() => {
|
||||
<!-- 插槽-卡片左侧侧 -->
|
||||
<template #title>
|
||||
<a-space :size="8" align="center">
|
||||
<a-button type="primary" :loading="tableState.loading" @click.prevent="fnChangShowType()">
|
||||
<a-button
|
||||
type="primary"
|
||||
:loading="tableState.loading"
|
||||
@click.prevent="fnChangShowType()"
|
||||
>
|
||||
<template #icon>
|
||||
<AreaChartOutlined />
|
||||
</template>
|
||||
@@ -937,8 +962,12 @@ onBeforeUnmount(() => {
|
||||
: t('views.perfManage.goldTarget.kpiTableTitle')
|
||||
}}
|
||||
</a-button>
|
||||
<a-button type="dashed" :loading="tableState.loading" @click.prevent="fnRecordExport()"
|
||||
v-show="tableState.showTable">
|
||||
<a-button
|
||||
type="dashed"
|
||||
:loading="tableState.loading"
|
||||
@click.prevent="fnRecordExport()"
|
||||
v-show="tableState.showTable"
|
||||
>
|
||||
<template #icon>
|
||||
<ExportOutlined />
|
||||
</template>
|
||||
@@ -958,8 +987,12 @@ onBeforeUnmount(() => {
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<TableColumnsDnd v-if="tableColumns.length > 0" :cache-id="`kpiTarget_${state.neType[0]}`"
|
||||
:columns="tableColumns" v-model:columns-dnd="tableColumnsDnd"></TableColumnsDnd>
|
||||
<TableColumnsDnd
|
||||
v-if="tableColumns.length > 0"
|
||||
:cache-id="`kpiTarget_${state.neType[0]}`"
|
||||
:columns="tableColumns"
|
||||
v-model:columns-dnd="tableColumnsDnd"
|
||||
></TableColumnsDnd>
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.sizeText') }}</template>
|
||||
<a-dropdown trigger="click" placement="bottomRight">
|
||||
@@ -969,7 +1002,10 @@ onBeforeUnmount(() => {
|
||||
</template>
|
||||
</a-button>
|
||||
<template #overlay>
|
||||
<a-menu :selected-keys="[tableState.size as string]" @click="fnTableSize">
|
||||
<a-menu
|
||||
:selected-keys="[tableState.size as string]"
|
||||
@click="fnTableSize"
|
||||
>
|
||||
<a-menu-item key="default">
|
||||
{{ t('common.size.default') }}
|
||||
</a-menu-item>
|
||||
@@ -998,19 +1034,37 @@ onBeforeUnmount(() => {
|
||||
size="small"
|
||||
/>
|
||||
</a-form-item> -->
|
||||
<a-form-item :label="t('views.perfManage.goldTarget.realTimeData')" name="chartRealTime">
|
||||
<a-switch :disabled="tableState.loading" v-model:checked="state.chartRealTime"
|
||||
:checked-children="t('common.switch.open')" :un-checked-children="t('common.switch.shut')"
|
||||
@change="fnRealTimeSwitch" size="small" />
|
||||
<a-form-item
|
||||
:label="t('views.perfManage.goldTarget.realTimeData')"
|
||||
name="chartRealTime"
|
||||
>
|
||||
<a-switch
|
||||
:disabled="tableState.loading"
|
||||
v-model:checked="state.chartRealTime"
|
||||
:checked-children="t('common.switch.open')"
|
||||
:un-checked-children="t('common.switch.shut')"
|
||||
@change="fnRealTimeSwitch"
|
||||
size="small"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</template>
|
||||
|
||||
<!-- 表格列表 -->
|
||||
<a-table v-show="tableState.showTable" class="table" row-key="id" :columns="tableColumnsDnd"
|
||||
:loading="tableState.loading" :data-source="tableState.data" :size="tableState.size"
|
||||
:pagination="tablePagination" :scroll="{ x: tableColumnsDnd.length * 200, y: 'calc(100vh - 480px)' }"
|
||||
@resizeColumn="(w: number, col: any) => (col.width = w)" :show-expand-column="false" @change="fnTableChange">
|
||||
<a-table
|
||||
v-show="tableState.showTable"
|
||||
class="table"
|
||||
row-key="id"
|
||||
:columns="tableColumnsDnd"
|
||||
:loading="tableState.loading"
|
||||
:data-source="tableState.data"
|
||||
:size="tableState.size"
|
||||
:pagination="tablePagination"
|
||||
:scroll="{ x: tableColumnsDnd.length * 200, y: 'calc(100vh - 480px)' }"
|
||||
@resizeColumn="(w: number, col: any) => (col.width = w)"
|
||||
:show-expand-column="false"
|
||||
@change="fnTableChange"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'timeGroup'">
|
||||
{{ parseDateToStr(+record.timeGroup) }}
|
||||
@@ -1020,15 +1074,40 @@ onBeforeUnmount(() => {
|
||||
|
||||
<!-- 图表 -->
|
||||
<div style="padding: 24px" v-show="!tableState.showTable">
|
||||
<div ref="kpiChartDom" class="chart-container" style="height: 450px; width: 100%"></div>
|
||||
<div
|
||||
ref="kpiChartDom"
|
||||
class="chart-container"
|
||||
style="height: 450px; width: 100%"
|
||||
></div>
|
||||
|
||||
<div class="table-container">
|
||||
<a-table :columns="statsColumns" :data-source="kpiStats" :pagination="false" :scroll="{ y: 250 }" size="small"
|
||||
:custom-row="record => ({
|
||||
onClick: () => handleRowClick(record),
|
||||
class: selectedRow.includes(record.kpiId) ? 'selected-row' : ''
|
||||
})
|
||||
" />
|
||||
<a-table
|
||||
:columns="statsColumns"
|
||||
:data-source="kpiStats"
|
||||
:pagination="false"
|
||||
:scroll="{ y: 250 }"
|
||||
size="small"
|
||||
:custom-row="
|
||||
record => ({
|
||||
onClick: () => handleRowClick(record),
|
||||
class: selectedRow.includes(record.kpiId) ? 'selected-row' : '',
|
||||
})
|
||||
"
|
||||
>
|
||||
<template #headerCell="{ column }">
|
||||
<template v-if="column.key === 'total'">
|
||||
<span>
|
||||
{{ t('views.perfManage.kpiOverView.totalValue') }}
|
||||
<a-tooltip placement="bottom">
|
||||
<template #title>
|
||||
<span>Sum within Time Range</span>
|
||||
</template>
|
||||
<InfoCircleOutlined />
|
||||
</a-tooltip>
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
|
||||
Reference in New Issue
Block a user