<template>
|
<el-dialog
|
class="limit-height"
|
:destroy-on-close="true"
|
v-model="dialogIsShow"
|
width="70%"
|
:close-on-click-modal="false"
|
@closed="closeDialog"
|
>
|
<template #header>
|
<div style="color: #fff">
|
<SvgIcon name="ele-Document" :size="16" style="margin-right: 3px; display: inline; vertical-align: middle" />
|
<span>选择指标数据</span>
|
</div>
|
</template>
|
<div class="flex-0 mb-3 flex items-center gap-2 justify-between font-bold">
|
<div class="">请勾选下方的指标,按条件筛选数据</div>
|
<!-- bug -->
|
<!-- <div class="flex items-center gap-2">
|
<p>已选择 {{ checkedCount }} 张业务表,共 {{ totalRecordCount }} 条记录</p>
|
<el-button link type="primary" @click="clearSelected">清空</el-button>
|
</div> -->
|
</div>
|
<AHMContainer class="flex-auto" type="card" v-loading="submitLoading">
|
<template #aside>
|
<!-- 目录树 -->
|
<LeftTreeByMgr
|
showCheckbox
|
v-loading="treeLoading"
|
class="h100"
|
ref="leftTreeRef"
|
:defaultProps="{
|
id: 'logicalId',
|
label: 'title',
|
children: 'children',
|
}"
|
@check="handleCheck"
|
defaultExpandAll
|
:treedata="listTreeData"
|
:show-title="false"
|
:show-more-operate="false"
|
:show-add="false"
|
:current-node-key="currentListID"
|
:folder-icon="(_, data) => data.type === 'group' || data.type === 'item'"
|
@click="handleClickNode"
|
>
|
</LeftTreeByMgr>
|
</template>
|
<template #header>
|
<TimeRange
|
ref="timeRangeRef"
|
:data="{
|
origin: {
|
time_step: TimeStepValue.Month,
|
},
|
}"
|
v-if="currentNode?.dateRange"
|
v-model="currentNode.dateRange"
|
@change="handleSearchInput"
|
/>
|
</template>
|
<template #main>
|
<div class="w100 h100">
|
<div class="h-full flex-column gap-2">
|
<!-- <div class="flex-0 flex-items-center flex-wrap">
|
<div class="ml-auto space-x-2 flex-items-center">
|
<DisplayMode
|
v-if="isChart"
|
:order="modeChangeOrder"
|
v-model="showMode"
|
:modeTypeMap="displayModeTypeMap"
|
@change="displayModeChange"
|
/>
|
<ColFilter class="flex-0 ml-auto" :column-list="tableCheckData" />
|
</div>
|
</div> -->
|
|
<ChartDisplay
|
v-if="currentNode?.values"
|
class="flex-auto"
|
v-show="showMode === DisplayModeType.Chart"
|
:values="currentNode?.values"
|
:mapRow="currentNode"
|
/>
|
</div>
|
</div>
|
</template>
|
</AHMContainer>
|
<template v-slot:footer>
|
<div>
|
<el-button @click="closeDialog">取 消</el-button>
|
<el-button type="primary" @click="submitFormValue">确 定</el-button>
|
</div>
|
</template>
|
</el-dialog>
|
</template>
|
|
<script setup lang="ts">
|
import { ElMessage } from 'element-plus';
|
import { computed, nextTick, ref, watch } from 'vue';
|
import {
|
DisplayModeType,
|
displayModeTypeMap,
|
TimeStepValue,
|
} from '../../../chatComponents/summaryCom/components/recordSet/components/types';
|
|
import TimeRange from '../../../chatComponents/summaryCom/components/recordSet/components/TimeRange.vue';
|
// import ChartDisplay from './ChartDisplay.vue';
|
// import TableSearch from './search/index.vue';
|
import ChartDisplay from './ChartDisplay.vue';
|
import * as attachApi from '/@/api/attach';
|
import DisplayMode from '/@/components/chat/chatComponents/summaryCom/components/recordSet/components/DisplayMode.vue';
|
import AHMContainer from '/@/components/layout/AHMContainer.vue';
|
import ColFilter from '/@/components/table/colFilter/ColFilter.vue';
|
import LeftTreeByMgr from '/@/components/tree/leftTreeByMgr.vue';
|
import { useCompRef } from '/@/utils/types';
|
import { convertListToTree, debounce, getRecentDateRange, travelTree } from '/@/utils/util';
|
|
import { formatDate } from '/@/utils/formatTime';
|
const dialogIsShow = defineModel({
|
type: Boolean,
|
});
|
const checkedNodes = ref([]);
|
|
const checkedItemNodes = computed(() => {
|
return checkedNodes.value.filter((item) => item.type === 'metric');
|
});
|
|
const timeRangeRef = useCompRef(TimeRange);
|
const resetBusinessTable = () => {
|
checkedNodes.value = [];
|
};
|
|
const emit = defineEmits(['submit']);
|
const closeDialog = () => {
|
dialogIsShow.value = false;
|
resetBusinessTable();
|
};
|
const handleCheck = async (data, obj) => {
|
checkedNodes.value = obj?.checkedNodes ?? [];
|
await getUnGetData(checkedItemNodes.value);
|
if (data.type === 'metric') {
|
handleClickNode(data);
|
}
|
};
|
|
const isChart = computed(() => {
|
return !!currentNode.value?.is_chart;
|
});
|
|
const showTable = computed(() => {
|
return !isChart.value || (isChart.value && showMode.value === DisplayModeType.List);
|
});
|
|
//#region ====================== 模式切换 ======================
|
const showMode = ref(DisplayModeType.Chart);
|
const modeChangeOrder = [DisplayModeType.List, DisplayModeType.Chart];
|
|
const isRendered = ref(false);
|
const displayModeChange = (val: DisplayModeType) => {
|
if (val === DisplayModeType.Chart) {
|
nextTick(() => {
|
isRendered.value = true;
|
});
|
}
|
};
|
//#endregion
|
const submitLoading = ref(false);
|
const getSubmitData = async (checkedList: any[]) => {
|
submitLoading.value = true;
|
await getUnGetData(checkedList).finally(() => {
|
submitLoading.value = false;
|
});
|
const tables = checkedList.map((item) => {
|
return {
|
title: item?.model?.TITLE,
|
columns: item.values?.columns,
|
values: item.values?.records,
|
};
|
});
|
return tables;
|
};
|
const submitFormValue = async () => {
|
const checkedList = leftTreeRef.value?.treeRef.getCheckedNodes().filter((item) => item.type === 'metric');
|
if (!checkedList?.length) {
|
ElMessage.warning('请勾选指标!');
|
return;
|
}
|
const data = await getSubmitData(checkedList);
|
emit('submit', data);
|
dialogIsShow.value = false;
|
};
|
//#region ====================== 左侧树数据,tree init ======================
|
const leftTreeRef = useCompRef(LeftTreeByMgr);
|
const treeLoading = ref(false);
|
const currentListID = computed(() => currentNode.value?.id);
|
|
const listTreeData = ref([]);
|
const currentNode = ref(null);
|
const getRowByLogicalId = (logicalId) => {
|
let row;
|
travelTree(listTreeData.value, (value, index, array, parent) => {
|
if (value.logicalId === logicalId) {
|
row = value;
|
|
return true;
|
}
|
});
|
return row;
|
};
|
const requestListTreeData = async (listData: any[]) => {
|
const listDataWithType = listData.map((item) => ({
|
id: item.id,
|
logicalId: `item-${item.id}`,
|
logicalParentId: `group-${item.group}`,
|
...item,
|
type: 'item',
|
}));
|
|
const groupList = Array.from(new Set(listDataWithType.filter((item) => item.group).map((item) => item.group))).map((item) => ({
|
id: item,
|
title: item,
|
logicalId: `group-${item}`,
|
type: 'group',
|
}));
|
const treeData = convertListToTree(listDataWithType.concat(groupList), {
|
ID: 'logicalId',
|
ParentID: 'logicalParentId',
|
Children: 'children',
|
});
|
|
const requestParams = listData.map((item) => {
|
return {
|
id: item.id,
|
name: item.title,
|
};
|
});
|
|
const p = Promise.all(
|
requestParams.map((item) => {
|
return attachApi.queryAttachMetricNamesByPost(item);
|
})
|
);
|
|
const res = await p;
|
|
const idMapMetricName = new Map(
|
requestParams.map((item, index) => {
|
return [item.id, res[index].values ?? []];
|
})
|
);
|
|
for (const metricItem of listDataWithType) {
|
const metricId = metricItem.id;
|
if (idMapMetricName.has(metricId)) {
|
const metricNames = idMapMetricName.get(metricId);
|
metricItem.children = metricNames.map((item) => {
|
const id = `${item.OTYPE}-${item.ONAME}`;
|
return {
|
metric: metricItem,
|
id,
|
logicalId: `metric-${id}`,
|
title: item.TITLE,
|
type: 'metric',
|
|
model: item,
|
};
|
});
|
}
|
}
|
return treeData;
|
};
|
|
const resetRight = () => {
|
showMode.value = DisplayModeType.Chart;
|
timeRangeRef.value?.resetQuickPickValue();
|
};
|
|
const handleClickNode = (data) => {
|
if (data.type === 'group' || data.type === 'item') {
|
ElMessage.warning('请选择指标');
|
return;
|
}
|
nextTick(() => {
|
leftTreeRef.value?.treeRef.setCurrentKey(data.logicalId);
|
});
|
currentNode.value = data;
|
resetRight();
|
|
getTableData();
|
};
|
const getListTreeData = async () => {
|
treeLoading.value = true;
|
const res = await attachApi.getAttachMetricListByPost().finally(() => {
|
treeLoading.value = false;
|
});
|
const listData = res.metrics || [];
|
|
listTreeData.value = await requestListTreeData(listData);
|
let firstListTreeNode;
|
travelTree(listTreeData.value, (value, index, array, parent) => {
|
if (value.type === 'metric') {
|
firstListTreeNode = value;
|
return true;
|
}
|
});
|
if (firstListTreeNode) {
|
handleClickNode(firstListTreeNode);
|
} else {
|
currentNode.value = null;
|
}
|
};
|
//#endregion
|
//#region ====================== 指标管理表格数据,table init ======================
|
const tableLoading = ref(false);
|
|
const getTableData = async () => {
|
if (!currentNode.value.values) {
|
handleSearchInput();
|
}
|
};
|
//#endregion
|
|
//#region ====================== 查询 ======================
|
|
const getSearchParams = (node) => {
|
if (!node.dateRange) {
|
const dateRange = getRecentDateRange(90).map((item) => formatDate(item));
|
node.dateRange = dateRange;
|
}
|
const metricsNameModel = JSON.stringify(node.model);
|
|
const params = {
|
id: node.metric?.id,
|
start_time: node.dateRange[0],
|
end_time: node.dateRange[1],
|
quota_keys: metricsNameModel,
|
limit:100
|
} as any;
|
|
return params;
|
};
|
|
const handleSearchItem = async (node) => {
|
const params = getSearchParams(node);
|
|
tableLoading.value = true;
|
const res = await attachApi.queryAttachMetricValuesByPost(params).finally(() => {
|
tableLoading.value = false;
|
});
|
node.values = res ?? {};
|
// node.values = parseRecordData(res, node.columns ?? []);
|
};
|
|
const handleSearchInput = async () => {
|
handleSearchItem(currentNode.value);
|
};
|
|
const getUnGetData = async (checkedList: any[]) => {
|
const getDataPromiseList = [];
|
for (const item of checkedList) {
|
if (!item.values) {
|
getDataPromiseList.push(handleSearchItem(item));
|
}
|
}
|
// 等待所有数据获取完成
|
await Promise.all(getDataPromiseList);
|
};
|
|
//#endregion
|
const getEleOrder = (order) => {
|
if (order === 'DESC') {
|
return 'descending';
|
} else if (order === 'ASC') {
|
return 'ascending';
|
} else {
|
return '';
|
}
|
};
|
|
watch(
|
() => dialogIsShow.value,
|
(val) => {
|
if (!val) return;
|
getListTreeData();
|
}
|
);
|
</script>
|
<style scoped lang="scss">
|
.set-permission {
|
padding-block: 16px;
|
padding-block-end: 0;
|
}
|
.set-form {
|
display: block;
|
box-sizing: border-box;
|
height: 100%;
|
padding-block: 16px;
|
.set-form-item {
|
font-weight: 500;
|
color: #667085;
|
font-size: 14px;
|
}
|
}
|
|
:deep(.el-dialog__body) {
|
height: calc(90vh - 111px) !important;
|
}
|
</style>
|
<style lang="scss">
|
.limit-height {
|
.el-dialog__body {
|
height: calc(90vh - 111px) !important;
|
display: flex;
|
flex-direction: column;
|
overflow: hidden;
|
}
|
}
|
|
.yw-layout-main {
|
.el-card__body {
|
padding: 10px;
|
}
|
}
|
</style>
|