增加黄金指标相关代码

This commit is contained in:
lai
2023-12-04 19:37:40 +08:00
parent b2b837623a
commit ab2154003e
4 changed files with 278 additions and 281 deletions

View File

@@ -8,7 +8,7 @@ import { parseObjLineToHump } from '@/utils/parse-utils';
* @returns object * @returns object
*/ */
export async function listgoldData(query: Record<string, any>) { export async function listgoldData(query: Record<string, any>) {
console.log(query); //console.log(query);
let totalSQL = 'select count(*) as total from gold_kpi where 1=1 '; let totalSQL = 'select count(*) as total from gold_kpi where 1=1 ';
let rowsSQL = let rowsSQL =
'SELECT gold_kpi.*,kpi_title.en_title FROM gold_kpi LEFT JOIN kpi_title on gold_kpi.kpi_id=kpi_title.kpi_id where 1=1 '; 'SELECT gold_kpi.*,kpi_title.en_title FROM gold_kpi LEFT JOIN kpi_title on gold_kpi.kpi_id=kpi_title.kpi_id where 1=1 ';
@@ -76,3 +76,85 @@ export async function listgoldData(query: Record<string, any>) {
} }
return result; return result;
} }
/**
* 查询黄金指标数据
* @param query 查询参数
* @returns object
*/
export async function goldData(query: Record<string, any>) {
//console.log(query);
// 发起请求
let insertKpiId: string[]=[];
let insertWhere: string[]=[];
query.goldArr.forEach((item: any)=> {
insertKpiId.push(`SUM(CASE WHEN kpi_id = '${item}' THEN value ELSE 0 END) AS ${item.split(".")[0]+'_'+item.split(".")[1]} `);
insertWhere.push(`'${item}'`);
})
const result = await request({
url: `/api/rest/databaseManagement/v1/select/omc_db/gold_kpi`,
method: 'get',
params: {
rowsSQL:`SELECT CONCAT(DATE_FORMAT(start_time, '%Y-%m-%d %H:'), LPAD(FLOOR(MINUTE(start_time) / ${query.particle}) * ${query.particle}, 2, '0'), ':00') AS time_interval,`+
insertKpiId.join(",")+
" FROM gold_kpi"+
` WHERE ne_type='UPF' and kpi_id in (${insertWhere.join(",")}) and start_time BETWEEN '${query.beginTime}' AND '${query.endTime}'`+
` GROUP BY DATE_FORMAT(start_time, '%Y-%m-%d %H:'), FLOOR(MINUTE(start_time) / ${query.particle})`+
" ORDER BY start_time",
},
timeout: 60_000,
});
// 解析数据
if (result.code === RESULT_CODE_SUCCESS) {
const data: DataList = {
total: 0,
rows: [],
code: result.code,
msg: result.msg,
};
result.data.data.forEach((item: any) => {
const itemData = item['gold_kpi'];
if (Array.isArray(itemData)) {
if (itemData.length === 1 && itemData[0]['total'] >= 0) {
data.total = itemData[0]['total'];
} else {
data.rows = itemData.map(v => parseObjLineToHump(v));
}
}
});
return data;
}
return result;
}
/**
* 查询网元可用黄金指标
* @param neType 网元类型
* @returns object
*/
export async function getGoldTitleByNE(neType: string) {
// 发起请求
const result = await request({
url: `/api/rest/databaseManagement/v1/elementType/omc_db/objectType/kpi_title`,
method: 'get',
params: {
SQL: `select * from kpi_title where ne_type = '${neType}' `,
},
});
// 解析数据
if (result.code === RESULT_CODE_SUCCESS && Array.isArray(result.data.data)) {
let data = result.data.data[0];
return Object.assign(result, {
data: parseObjLineToHump(data['kpi_title']),
});
}
return result;
}

View File

@@ -628,6 +628,8 @@ export default {
value:'Value', value:'Value',
startTime:'Start Time', startTime:'Start Time',
endTime:'End Time', endTime:'End Time',
particle: 'Particle Ssize',
timeFrame: 'Time Range',
} }
}, },
traceManage: { traceManage: {

View File

@@ -627,7 +627,9 @@ export default {
enTitle:'黄金指标项', enTitle:'黄金指标项',
value:'值', value:'值',
startTime:'开始时间', startTime:'开始时间',
endTime:'结束时间' endTime:'结束时间',
particle:'颗粒度',
timeFrame:'时间范围',
} }
}, },
traceManage: { traceManage: {

View File

@@ -1,334 +1,245 @@
<script setup lang="ts"> <script setup lang="ts">
import { useRoute } from 'vue-router';
import { reactive, ref, onMounted, toRaw } from 'vue'; import { reactive, ref, onMounted, toRaw } from 'vue';
import { PageContainer } from 'antdv-pro-layout'; import { PageContainer } from 'antdv-pro-layout';
import { Modal } from 'ant-design-vue/lib'; import { message } from 'ant-design-vue/lib';
import { SizeType } from 'ant-design-vue/lib/config-provider';
import { MenuInfo } from 'ant-design-vue/lib/menu/src/interface';
import { ColumnsType } from 'ant-design-vue/lib/table';
import { parseDateToStr } from '@/utils/date-utils';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants'; import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import { listgoldData } from '@/api/perfManage/goldTarget';
import useNeInfoStore from '@/store/modules/neinfo'; import useNeInfoStore from '@/store/modules/neinfo';
import useDictStore from '@/store/modules/dict';
import useI18n from '@/hooks/useI18n'; import useI18n from '@/hooks/useI18n';
const { getDict } = useDictStore(); import { getGoldTitleByNE, goldData } from '@/api/perfManage/goldTarget';
const { t } = useI18n();
const route = useRoute();
/**路由标题 */ const { t, currentLocale } = useI18n();
let title = ref<string>((route.meta.title as string) ?? '标题');
/**网元参数 */
let neCascaderOptions = ref<Record<string, any>[]>([]);
/**记录开始结束时间 */ /**记录开始结束时间 */
let queryRangePicker = ref<[string, string]>(['', '']); let queryRangePicker = ref<[string, string]>(['', '']);
/**查询参数 */ /**查询参数 */
let queryParams = reactive({ let queryParams: any = reactive({
/**网元类型 */ /**已勾选指标 */
goldArr:[],
/**告警设备类型 */
neType: '', neType: '',
/**记录时间 */ /**告警网元标识 */
neId: '',
/**颗粒度 */
particle: '',
beginTime: '', beginTime: '',
endTime: '', endTime: '',
/**排序字段 */
sortField: 'value',
/**排序方式 */
sortOrder: 'asc',
/**当前页数 */
pageNum: 1,
/**每页条数 */
pageSize: 20,
}); });
/**查询参数重置 */ /**对象信息状态类型 */
function fnQueryReset() { type StateType = {
queryParams = Object.assign(queryParams, { /**网元类型 */
neType: '', neType: string[];
beginTime: '', /**制表网元类型 */
endTime: '', designNeType: string;
sortField: 'value', /**黄金指标集 tree */
sortOrder: 'asc', designTreeData: any[];
pageNum: 1, /**指标勾选集*/
pageSize: 20, goldArr: any[];
}); /**表单数据 */
queryRangePicker.value = ['', '']; from: Record<string, any>;
tablePagination.current = 1;
tablePagination.pageSize = 20;
fnGetList();
}
/**表格状态类型 */
type TabeStateType = {
/**加载等待 */
loading: boolean;
/**紧凑型 */
size: SizeType;
/**搜索栏 */
seached: boolean;
/**记录数据 */
data: object[];
}; };
/**表格状态 */ /**对象信息状态 */
let tableState: TabeStateType = reactive({ let state: StateType = reactive({
loading: false, neType: [],
size: 'middle', designNeType: '',
seached: true, designTreeData: [],
data: [], goldArr: [],
from: {
uploadLoading: false,
sendLoading: false,
},
}); });
/**表格字段列 */ /**网元类型选择对应修改 */
let tableColumns: ColumnsType = [ function fnNeChange(keys: any, _: any) {
{ // 不是同类型时需要重新加载
title: t('views.perfManage.goldTarget.type'), if (state.designNeType !== keys[0]) {
dataIndex: 'neType', state.designTreeData = [];
align: 'center',
},
{
title: t('views.perfManage.goldTarget.enTitle'),
dataIndex: 'enTitle',
align: 'center',
},
{
title: t('views.perfManage.goldTarget.value'),
dataIndex: 'value',
key: 'value',
align: 'center',
sorter: true,
},
{
title: t('views.perfManage.goldTarget.startTime'),
dataIndex: 'startTime',
key: 'start_time',
align: 'center',
customRender(opt) {
if (!opt.value) return '';
return parseDateToStr(opt.value);
},
sorter: true,
},
{
title: t('views.perfManage.goldTarget.endTime'),
dataIndex: 'endTime',
align: 'center',
customRender(opt) {
if (!opt.value) return '';
return parseDateToStr(opt.value);
},
},
];
/**表格分页器参数 */
let tablePagination = reactive({
/**当前页数 */
current: 1,
/**每页条数 */
pageSize: 20,
/**默认的每页条数 */
defaultPageSize: 20,
/**指定每页可以显示多少条 */
pageSizeOptions: ['10', '20', '50', '100'],
/**只有一页时是否隐藏分页器 */
hideOnSinglePage: false,
/**是否可以快速跳转至某页 */
showQuickJumper: true,
/**是否可以改变 pageSize */
showSizeChanger: true,
/**数据总数 */
total: 0,
showTotal: (total: number) => t('common.tablePaginationTotal', { total }),
onChange: (page: number, pageSize: number) => {
tablePagination.current = page;
tablePagination.pageSize = pageSize;
queryParams.pageNum = page;
queryParams.pageSize = pageSize;
fnGetList(); fnGetList();
}, }
});
/**表格紧凑型变更操作 */
function fnTableSize({ key }: MenuInfo) {
tableState.size = key as SizeType;
} }
/**查询黄金指标列表, pageNum初始页数 */ /**查询可选命令列表 */
function fnGetList(pageNum?: number) { function fnGetList() {
if (tableState.loading) return; const neType = queryParams.neType[0];
tableState.loading = true; state.designNeType = neType;
if (pageNum) { var language = currentLocale.value.split('_')[0];
queryParams.pageNum = pageNum; // console.log(language)
} if (language === 'zh') language = 'cn';
getGoldTitleByNE(neType).then(res => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
// 构建自动完成筛选结构
const autoCompleteArr: Record<string, any>[] = [];
// 构建树结构
const treeArr: Record<string, any>[] = [];
for (const item of res.data) {
const id = item['id'];
const kpiDisplay = item[`${language}Title`];
const kpiValue = item[`kpiId`];
treeArr.push({
key: kpiValue,
title: kpiDisplay,
});
}
state.designTreeData = treeArr;
} else {
message.warning({
content: t('common.getInfoFail'),
duration: 2,
});
}
});
}
/**筛选条件进行制图 */
function fnDesign() {
const neType=queryParams.neType[0];
if (!queryRangePicker.value) { if (!queryRangePicker.value) {
queryRangePicker.value = ['', '']; queryRangePicker.value = ['', ''];
} }
queryParams.beginTime = queryRangePicker.value[0]; queryParams.beginTime = queryRangePicker.value[0];
queryParams.endTime = queryRangePicker.value[1]; queryParams.endTime = queryRangePicker.value[1];
listgoldData(toRaw(queryParams)).then(res => { console.log(toRaw(queryParams));
goldData(queryParams).then(res => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.rows)) { if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.rows)) {
tablePagination.total = res.total; console.log(res.rows);
tableState.data = res.rows; } else {
message.warning({
content: t('common.getInfoFail'),
duration: 2,
});
} }
tableState.loading = false;
}); });
} }
/**表格分页、排序、筛选变化时触发操作, 排序方式,取值为 ascend descend */ /**勾选指标的变动 */
function fnTableChange(pagination: any, filters: any, sorter: any, extra: any) { function fnTreeCheck(value: any, _: any) {
console.log(sorter); queryParams.goldArr = value;
const { columnKey, order } = sorter;
if (order) {
queryParams.sortField = columnKey;
queryParams.sortOrder = order.replace('end', '');
} else {
queryParams.sortOrder = 'asc';
}
fnGetList(1);
} }
onMounted(() => { onMounted(() => {
// 获取网元网元列表 // 获取网元网元列表
useNeInfoStore().fnNelist(); useNeInfoStore()
// 获取列表数据 .fnNelist()
fnGetList(); .then(res => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
if (res.data.length > 0) {
// 过滤不可用的网元
neCascaderOptions.value = useNeInfoStore().getNeCascaderOtions.filter(
(item: any) => {
return !['OMC'].includes(item.value);
}
);
// 默认选择AMF
const item = neCascaderOptions.value.find(s => s.value === 'AMF');
if (item && item.children) {
const info = item.children[0];
queryParams.neType = [info.neType, info.neId];
} else {
const info = neCascaderOptions.value[0].children[0];
queryParams.neType = [info.neType, info.neId];
}
fnGetList();
}
} else {
message.warning({
content: t('common.noData'),
duration: 2,
});
}
});
}); });
</script> </script>
<template> <template>
<PageContainer> <PageContainer>
<a-card <a-row :gutter="16">
v-show="tableState.seached" <a-col :span="9">
:bordered="false" <!-- 命令导航 -->
:body-style="{ marginBottom: '24px', paddingBottom: 0 }" <a-card
> size="small"
<!-- 表格搜索栏 --> :bordered="false"
<a-form :model="queryParams" name="queryParams" layout="horizontal"> :title="t('views.mmlManage.cmdTitle')"
<a-row :gutter="16"> >
<a-col :lg="6" :md="12" :xs="24"> <a-form :model="queryParams" name="queryParams" layout="horizontal">
<a-row :gutter="16">
<a-col :lg="12" :md="12" :xs="24">
<a-form-item
name="neType"
:label="t('views.traceManage.task.neType')"
>
<a-cascader
v-model:value="queryParams.neType"
:options="neCascaderOptions"
@change="fnNeChange"
:allow-clear="false"
:placeholder="t('common.selectPlease')"
/>
</a-form-item>
</a-col>
</a-row>
<a-form-item <a-form-item
:label="t('views.perfManage.goldTarget.type')" :label="t('views.perfManage.goldTarget.timeFrame')"
name="neType" name="eventTime"
>
<a-auto-complete
v-model:value="queryParams.neType"
:options="useNeInfoStore().getNeSelectOtions"
allow-clear
/>
</a-form-item>
</a-col>
<a-col :lg="8" :md="12" :xs="24">
<a-form-item
:label="t('views.perfManage.goldTarget.startTime')"
name="queryRangePicker"
> >
<a-range-picker <a-range-picker
v-model:value="queryRangePicker" v-model:value="queryRangePicker"
allow-clear
bordered
show-time
value-format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss"
format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD HH:mm:ss"
style="width: 100%" show-time
></a-range-picker> />
</a-form-item> </a-form-item>
</a-col>
<a-col :lg="6" :md="12" :xs="24"> <a-row :gutter="16">
<a-form-item> <a-col :lg="12" :md="12" :xs="24">
<a-space :size="8"> <a-form-item
<a-button type="primary" @click.prevent="fnGetList(1)"> :label="t('views.perfManage.goldTarget.particle')"
<template #icon><SearchOutlined /></template> name="particle"
{{ t('common.search') }}
</a-button>
<a-button type="default" @click.prevent="fnQueryReset">
<template #icon><ClearOutlined /></template>
{{ t('common.reset') }}
</a-button>
</a-space>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false" :body-style="{ padding: '0px' }">
<!-- 插槽-卡片左侧侧 -->
<template #title> </template>
<!-- 插槽-卡片右侧 -->
<template #extra>
<a-space :size="8" align="center">
<a-tooltip>
<template #title>{{ t('common.searchBarText') }}</template>
<a-switch
v-model:checked="tableState.seached"
:checked-children="t('common.switch.show')"
:un-checked-children="t('common.switch.hide')"
size="small"
/>
</a-tooltip>
<a-tooltip>
<template #title>{{ t('common.reloadText') }}</template>
<a-button type="text" @click.prevent="fnGetList()">
<template #icon><ReloadOutlined /></template>
</a-button>
</a-tooltip>
<a-tooltip>
<template #title>{{ t('common.sizeText') }}</template>
<a-dropdown trigger="click" placement="bottomRight">
<a-button type="text">
<template #icon><ColumnHeightOutlined /></template>
</a-button>
<template #overlay>
<a-menu
:selected-keys="[tableState.size as string]"
@click="fnTableSize"
> >
<a-menu-item key="default"> <a-select
{{ t('common.size.default') }} v-model:value="queryParams.particle"
</a-menu-item> :placeholder="t('common.selectPlease')"
<a-menu-item key="middle"> :options="[
{{ t('common.size.middle') }} { label: '15M', value: '15' },
</a-menu-item> { label: '30M', value: '30' },
<a-menu-item key="small"> { label: '60M', value: '60' },
{{ t('common.size.small') }} ]"
</a-menu-item> />
</a-menu> </a-form-item>
</template> </a-col>
</a-dropdown> <a-col :lg="12" :md="12" :xs="24">
</a-tooltip> <a-form-item>
</a-space> <a-space :size="8">
</template> <a-button type="primary" @click.prevent="fnDesign()">
<template #icon><SearchOutlined /></template>
<!-- 表格列表 --> {{ t('common.search') }}
<a-table </a-button>
class="table" </a-space>
row-key="id" </a-form-item>
:columns="tableColumns" </a-col>
:loading="tableState.loading" </a-row>
:data-source="tableState.data" </a-form>
:size="tableState.size" <a-form layout="vertical" autocomplete="off">
@change="fnTableChange" <a-form-item name="goldTree" v-if="state.designTreeData.length > 0">
:pagination="tablePagination" <a-directory-tree
:scroll="{ x: true }" :tree-data="state.designTreeData"
> checkable
<template #bodyCell="{ column, record }"> default-expand-all
<template v-if="column.key === 'alarmTitle'"> @check="fnTreeCheck"
<a-tooltip> ></a-directory-tree>
<template #title>{{ record.operResult }}</template> </a-form-item>
<div class="alarmTitleText">{{ record.alarmTitle }}</div> </a-form>
</a-tooltip> </a-card>
</template> </a-col>
</template> <a-col :span="15"> </a-col>
</a-table> </a-row>
</a-card>
</PageContainer> </PageContainer>
</template> </template>
<style lang="less" scoped> <style lang="less" scoped></style>
.table :deep(.ant-pagination) {
padding: 0 24px;
}
.alarmTitleText {
max-width: 300px;
cursor: pointer;
}
</style>