优化KPI展示

This commit is contained in:
lai
2025-02-13 19:32:04 +08:00
parent 8bfa73a67a
commit 4b032d74be
4 changed files with 75 additions and 100 deletions

View File

@@ -964,6 +964,7 @@ export default {
expressionModal:'Expression Modal', expressionModal:'Expression Modal',
expressionErrorTip:'Please check the expression, the wrong indicator is {kpiId}', expressionErrorTip:'Please check the expression, the wrong indicator is {kpiId}',
expressionNoIdTip:'Please check the expression, no valid indicator is found', expressionNoIdTip:'Please check the expression, no valid indicator is found',
unitSelect:'To better display the image, the same unit needs to be selected. The current unit is:',
}, },
kpiKeyTarget:{ kpiKeyTarget:{
"time":"Time", "time":"Time",

View File

@@ -964,6 +964,7 @@ export default {
expressionModal:'表达式模块', expressionModal:'表达式模块',
expressionErrorTip:'请检查表达式,错误的指标为{kpiId}', expressionErrorTip:'请检查表达式,错误的指标为{kpiId}',
expressionNoIdTip:'请检查表达式,没有找到任何有效的指标', expressionNoIdTip:'请检查表达式,没有找到任何有效的指标',
unitSelect:'为更好展示图需选择相同单位,当前单位为:',
}, },
kpiKeyTarget:{ kpiKeyTarget:{
"time":"时间", "time":"时间",

View File

@@ -242,6 +242,13 @@ const statsColumns: TableColumnType<any>[] = [
key: 'title', key: 'title',
width: '65%', width: '65%',
}, },
{
title: t('views.perfManage.kpiOverView.totalValue'),
dataIndex: 'total',
key: 'total',
width: '12%',
sortDirections: ['ascend', 'descend'],
},
{ {
title: t('views.perfManage.kpiOverView.avgValue'), title: t('views.perfManage.kpiOverView.avgValue'),
dataIndex: 'avg', dataIndex: 'avg',
@@ -356,6 +363,7 @@ function fnGetListTitle() {
dataIndex: kpiValue, dataIndex: kpiValue,
align: 'left', align: 'left',
key: kpiValue, key: kpiValue,
unit: item[`unit`],
resizable: true, resizable: true,
width: 100, width: 100,
minWidth: 150, minWidth: 150,
@@ -448,16 +456,17 @@ function fnGetList() {
const total = Number( const total = Number(
values.reduce((sum, val) => sum + val, 0).toFixed(2) values.reduce((sum, val) => sum + val, 0).toFixed(2)
); );
// 计算平均值 // 计算平均值
const avg = const avg =
values.length > 0 ? Number((total / values.length).toFixed(2)) : 0; values.length > 0 ? Number((total / values.length).toFixed(2)) : 0;
kpiStats.value.push({ kpiStats.value.push({
kpiId: columns.key, kpiId: columns.key,
title: columns.title, title: columns.title,
unit: columns.unit,
max: values.length > 0 ? Math.max(...values) : 0, max: values.length > 0 ? Math.max(...values) : 0,
min: values.length > 0 ? Math.min(...values) : 0, min: values.length > 0 ? Math.min(...values) : 0,
avg, avg,
total: total,
}); });
} }
} }
@@ -606,7 +615,7 @@ function fnRanderChartData() {
for (const item of orgData) { for (const item of orgData) {
const keys = Object.keys(item); const keys = Object.keys(item);
//console.log(keys,item);// //console.log(keys,item);
for (const y of chartDataYSeriesData) { for (const y of chartDataYSeriesData) {
for (const key of keys) { for (const key of keys) {
if (y.key === key) { if (y.key === key) {
@@ -744,25 +753,42 @@ function wsMessage(res: Record<string, any>) {
// 添加一个变量来跟踪当前选中的行 // 添加一个变量来跟踪当前选中的行
const selectedRow = ref<string[]>([]); const selectedRow = ref<string[]>([]);
const selectedUnit = ref<string | null>(null);
// 添加处理行点击的方法 // 添加处理行点击的方法
function handleRowClick(record: any) { function handleRowClick(record: any) {
const index = selectedRow.value.indexOf(record.kpiId); const index = selectedRow.value.indexOf(record.kpiId);
console.log(record)
// 如果已经选中,取消选中 // 如果已经选中,取消选中
if (index > -1) { if (index > -1) {
selectedRow.value.splice(index, 1); selectedRow.value.splice(index, 1);
chartLegendSelected[record.title] = false; chartLegendSelected[record.title] = false;
// 如果取消选中的是最后一个,重置 selectedUnit
if (selectedRow.value.length === 0) {
selectedUnit.value = null;
}
} else { } else {
// 检查单位是否一致
if (selectedUnit.value && selectedUnit.value !== record.unit) {
message.error(`${t('views.perfManage.customTarget.unitSelect')} ${selectedUnit.value}`);
return;
}
// 添加新的选中项 // 添加新的选中项
selectedRow.value.push(record.kpiId); selectedRow.value.push(record.kpiId);
// 设置选中的单位
if (!selectedUnit.value) {
selectedUnit.value = record.unit;
}
// 如果只有一个选中项,重置为 false // 如果只有一个选中项,重置为 false
if (selectedRow.value.length === 1) { if (selectedRow.value.length === 1) {
Object.keys(chartLegendSelected).forEach(key => { Object.keys(chartLegendSelected).forEach(key => {
chartLegendSelected[key] = false; chartLegendSelected[key] = false;
}); });
} }
chartLegendSelected[record.title] = true; chartLegendSelected[record.title] = true;
} }
@@ -914,50 +940,28 @@ onBeforeUnmount(() => {
<template> <template>
<PageContainer> <PageContainer>
<a-card <a-card v-show="tableState.seached" :bordered="false" :body-style="{ marginBottom: '24px', paddingBottom: 0 }">
v-show="tableState.seached"
:bordered="false"
:body-style="{ marginBottom: '24px', paddingBottom: 0 }"
>
<!-- 表格搜索栏 --> <!-- 表格搜索栏 -->
<a-form :model="queryParams" name="queryParamsFrom" layout="horizontal"> <a-form :model="queryParams" name="queryParamsFrom" layout="horizontal">
<a-row :gutter="16"> <a-row :gutter="16">
<a-col :lg="6" :md="12" :xs="24"> <a-col :lg="6" :md="12" :xs="24">
<a-form-item name="neType" :label="t('views.ne.common.neType')"> <a-form-item name="neType" :label="t('views.ne.common.neType')">
<a-cascader <a-cascader v-model:value="state.neType" :options="neCascaderOptions" :allow-clear="false"
v-model:value="state.neType" :placeholder="t('common.selectPlease')" />
:options="neCascaderOptions"
:allow-clear="false"
:placeholder="t('common.selectPlease')"
/>
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :lg="10" :md="12" :xs="24"> <a-col :lg="10" :md="12" :xs="24">
<a-form-item <a-form-item :label="t('views.perfManage.goldTarget.timeFrame')" name="timeFrame">
:label="t('views.perfManage.goldTarget.timeFrame')" <a-range-picker v-model:value="queryRangePicker" bordered :allow-clear="false"
name="timeFrame" :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss" value-format="x" :presets="ranges"
> style="width: 100%"></a-range-picker>
<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"
:presets="ranges"
style="width: 100%"
></a-range-picker>
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :lg="2" :md="12" :xs="24"> <a-col :lg="2" :md="12" :xs="24">
<a-form-item> <a-form-item>
<a-space :size="8"> <a-space :size="8">
<a-button <a-button type="primary" :loading="tableState.loading" @click.prevent="fnGetListTitle()">
type="primary"
:loading="tableState.loading"
@click.prevent="fnGetListTitle()"
>
<template #icon> <template #icon>
<SearchOutlined /> <SearchOutlined />
</template> </template>
@@ -974,11 +978,7 @@ onBeforeUnmount(() => {
<!-- 插槽-卡片左侧侧 --> <!-- 插槽-卡片左侧侧 -->
<template #title> <template #title>
<a-space :size="8" align="center"> <a-space :size="8" align="center">
<a-button <a-button type="primary" :loading="tableState.loading" @click.prevent="fnChangShowType()">
type="primary"
:loading="tableState.loading"
@click.prevent="fnChangShowType()"
>
<template #icon> <template #icon>
<AreaChartOutlined /> <AreaChartOutlined />
</template> </template>
@@ -988,12 +988,8 @@ onBeforeUnmount(() => {
: t('views.perfManage.goldTarget.kpiTableTitle') : t('views.perfManage.goldTarget.kpiTableTitle')
}} }}
</a-button> </a-button>
<a-button <a-button type="dashed" :loading="tableState.loading" @click.prevent="fnRecordExport()"
type="dashed" v-show="tableState.showTable">
:loading="tableState.loading"
@click.prevent="fnRecordExport()"
v-show="tableState.showTable"
>
<template #icon> <template #icon>
<ExportOutlined /> <ExportOutlined />
</template> </template>
@@ -1013,12 +1009,8 @@ onBeforeUnmount(() => {
</template> </template>
</a-button> </a-button>
</a-tooltip> </a-tooltip>
<TableColumnsDnd <TableColumnsDnd v-if="tableColumns.length > 0" :cache-id="`kpiTarget_${state.neType[0]}`"
v-if="tableColumns.length > 0" :columns="tableColumns" v-model:columns-dnd="tableColumnsDnd"></TableColumnsDnd>
:cache-id="`kpiTarget_${state.neType[0]}`"
:columns="tableColumns"
v-model:columns-dnd="tableColumnsDnd"
></TableColumnsDnd>
<a-tooltip> <a-tooltip>
<template #title>{{ t('common.sizeText') }}</template> <template #title>{{ t('common.sizeText') }}</template>
<a-dropdown trigger="click" placement="bottomRight"> <a-dropdown trigger="click" placement="bottomRight">
@@ -1028,10 +1020,7 @@ onBeforeUnmount(() => {
</template> </template>
</a-button> </a-button>
<template #overlay> <template #overlay>
<a-menu <a-menu :selected-keys="[tableState.size as string]" @click="fnTableSize">
:selected-keys="[tableState.size as string]"
@click="fnTableSize"
>
<a-menu-item key="default"> <a-menu-item key="default">
{{ t('common.size.default') }} {{ t('common.size.default') }}
</a-menu-item> </a-menu-item>
@@ -1060,61 +1049,32 @@ onBeforeUnmount(() => {
size="small" size="small"
/> />
</a-form-item> --> </a-form-item> -->
<a-form-item <a-form-item :label="t('views.perfManage.goldTarget.realTimeData')" name="chartRealTime">
:label="t('views.perfManage.goldTarget.realTimeData')" <a-switch :disabled="tableState.loading" v-model:checked="state.chartRealTime"
name="chartRealTime" :checked-children="t('common.switch.open')" :un-checked-children="t('common.switch.shut')"
> @change="fnRealTimeSwitch" size="small" />
<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-item>
</a-form> </a-form>
</template> </template>
<!-- 表格列表 --> <!-- 表格列表 -->
<a-table <a-table v-show="tableState.showTable" class="table" row-key="id" :columns="tableColumnsDnd"
v-show="tableState.showTable" :loading="tableState.loading" :data-source="tableState.data" :size="tableState.size"
class="table" :pagination="tablePagination" :scroll="{ x: tableColumnsDnd.length * 200, y: 'calc(100vh - 480px)' }"
row-key="id" @resizeColumn="(w: number, col: any) => (col.width = w)" :show-expand-column="false" @change="fnTableChange">
: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> </a-table>
<!-- 图表 --> <!-- 图表 -->
<div style="padding: 24px" v-show="!tableState.showTable"> <div style="padding: 24px" v-show="!tableState.showTable">
<div <div ref="kpiChartDom" class="chart-container" style="height: 450px; width: 100%"></div>
ref="kpiChartDom"
class="chart-container"
style="height: 450px; width: 100%"
></div>
<div class="table-container"> <div class="table-container">
<a-table <a-table :columns="statsColumns" :data-source="kpiStats" :pagination="false" :scroll="{ y: 250 }" size="small"
:columns="statsColumns" :custom-row="record => ({
:data-source="kpiStats"
:pagination="false"
:scroll="{ y: 250 }"
size="small"
:custom-row="
record => ({
onClick: () => handleRowClick(record), onClick: () => handleRowClick(record),
class: selectedRow.includes(record.kpiId) ? 'selected-row' : '', class: selectedRow.includes(record.kpiId) ? 'selected-row' : '',
}) })
" ">
>
<template #headerCell="{ column }"> <template #headerCell="{ column }">
<template v-if="column.key === 'total'"> <template v-if="column.key === 'total'">
<span> <span>
@@ -1169,6 +1129,14 @@ onBeforeUnmount(() => {
</span> </span>
</template> </template>
</template> </template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'avg'">
<span v-if="record.unit !== '%'">-</span>
</template>
<template v-if="column.key === 'total'">
<span v-if="record.unit == '%'">-</span>
</template>
</template>
</a-table> </a-table>
</div> </div>
</div> </div>

View File

@@ -131,6 +131,9 @@ type TabeStateType = {
selectedRowKeys: (string | number)[]; selectedRowKeys: (string | number)[];
}; };
//是否显示type框
const drawerVisible = ref(true);
/**表格状态 */ /**表格状态 */
let tableState: TabeStateType = reactive({ let tableState: TabeStateType = reactive({
loading: false, loading: false,
@@ -502,9 +505,11 @@ onMounted(() => {
message.error(t('views.system.dictData.typeDataErr'), 3); message.error(t('views.system.dictData.typeDataErr'), 3);
} }
}); });
drawerVisible.value = true;
} else { } else {
// 获取列表数据 // 获取列表数据
fnGetList(); fnGetList();
drawerVisible.value = false;
} }
}); });
</script> </script>
@@ -881,7 +886,7 @@ onMounted(() => {
default-value="sys_oper_type" default-value="sys_oper_type"
:placeholder="t('common.selectPlease')" :placeholder="t('common.selectPlease')"
:options="dict.sysDictType" :options="dict.sysDictType"
:disabled="true" :disabled="drawerVisible"
> >
</a-select> </a-select>
</a-form-item> </a-form-item>