yangyin
2024-11-15 ec3711218f166f5e7927fd577b8a2db9776e66e9
src/views/project/yw/systemManage/metricMgr/MetricDetail.vue
@@ -1,115 +1,95 @@
<template>
   <div class="flex flex-col h100">
      <el-row class="w100 h100">
         <el-col :span="17">
         <el-col :span="17" class="h-full">
            <div class="h100 relative">
               <div class="ml-6 h100">
                  <el-tabs v-model="state.activeMetricName" @tab-change="handleClick" class="h100">
                     <el-tab-pane label="基础信息" name="basicInformation">
                        <div class="h100">
                           <el-descriptions title="指标信息" :column="2">
                              <el-descriptions-item label="指标名称:">{{
                                 state.descriptionQuotaItems.title ? state.descriptionQuotaItems.title : '-'
                           <el-descriptions title="指标信息">
                              <el-descriptions-item label="指标名称:" :span="2">{{
                                 state.metricBasicInfo.descriptionQuotaItems.title ? state.metricBasicInfo.descriptionQuotaItems.title : '-'
                              }}</el-descriptions-item>
                              <el-descriptions-item label="指标全称:">{{
                                 state.descriptionQuotaItems.full_name ? state.descriptionQuotaItems.full_name : '-'
                              <el-descriptions-item label="指标全称:" :span="2">{{
                                 state.metricBasicInfo.descriptionQuotaItems.full_name
                                    ? state.metricBasicInfo.descriptionQuotaItems.full_name
                                    : '-'
                              }}</el-descriptions-item>
                              <el-descriptions-item label="指标定义:">{{
                                 state.descriptionQuotaItems.metrics_define ? state.descriptionQuotaItems.metrics_define : '-'
                              <el-descriptions-item label="指标定义:" :span="3">{{
                                 state.metricBasicInfo.descriptionQuotaItems.metrics_define
                                    ? state.metricBasicInfo.descriptionQuotaItems.metrics_define
                                    : '-'
                              }}</el-descriptions-item>
                              <el-descriptions-item label="类别:">
                              <el-descriptions-item label="类别:" :span="2">
                                 {{
                                    state.descriptionQuotaItems.metrics_type ? state.descriptionQuotaItems.metrics_type : '-'
                                    state.metricBasicInfo.descriptionQuotaItems.metrics_type
                                       ? state.metricBasicInfo.descriptionQuotaItems.metrics_type
                                       : '-'
                                 }}</el-descriptions-item
                              >
                              <el-descriptions-item label="重要性:">
                                 {{ eMetrics_Ops[state.descriptionQuotaItems.metrics_important] }}
                              <el-descriptions-item label="重要性:" :span="2">
                                 {{ eMetrics_Ops[state.metricBasicInfo.descriptionQuotaItems.metrics_important] }}
                              </el-descriptions-item>
                              <el-descriptions-item label="计算方法:">
                                 {{ state.descriptionQuotaItems.calcu_method ? state.descriptionQuotaItems.calcu_method : '-' }}
                              <el-descriptions-item label="计算方法:" :span="3">
                                 {{
                                    state.metricBasicInfo.descriptionQuotaItems.calcu_method
                                       ? state.metricBasicInfo.descriptionQuotaItems.calcu_method
                                       : '-'
                                 }}
                              </el-descriptions-item>
                           </el-descriptions>
                           <el-divider />
                        </div>
                     </el-tab-pane>
                     <el-tab-pane label="指标探索" name="indicatorExploration">
                        <div class="h100">
                           <div class="set_explore">
                              <div class="set_explore_pad">
                                 <el-form ref="exploreFormRef" :model="state.exploreForm" label-width="80px" label-position="left">
                                    <el-form-item label="日期区间:">
                                       <div style="width: 300px">
                                          <el-date-picker
                                             v-model="state.exploreForm.dateRangeExplore"
                                             type="daterange"
                                             range-separator="~"
                                             value-format="YYYY-MM-DD HH:mm:ss"
                                             :default-time="defaultTime"
                                             @change="getDateTime"
                                             :disabled-date="disablesDate"
                     <el-tab-pane label="指标探索" name="indicatorExploration" class="h-full">
                        <div class="h-full flex-column">
                           <el-form :model="dialogFormValue" class="flex-0" ref="dialogFormRef" :rules="dialogFormRules">
                              <el-form-item label="日期区间:" prop="rangValue" v-if="currentMetrics?.is_time_values ?? true">
                                 <TimeRange v-model="dialogFormValue.rangValue" @change="query(false)" />
                              </el-form-item>
                              <el-row :gutter="35">
                                 <el-col :span="12" class="mb20">
                                    <el-form-item label="分组维度:" prop="rangValue">
                                       <el-select v-model="dialogFormValue.groupDimList" multiple @change="query(false)">
                                          <el-option
                                             v-for="item in currentMetrics?.dimensions ?? []"
                                             :key="item.id"
                                             :label="item.title"
                                             :value="item.id"
                                          />
                                       </div>
                                    </el-form-item>
                                    <el-form-item label="维度下钻:">
                                       <el-select v-model="state.exploreForm.dimensionDrilling" autocomplete="off" style="width: 226.4px" clearable>
                                          <el-option
                                             v-for="item in Object.keys(eDrilling_Ops)"
                                             :key="item"
                                             :value="parseInt(item)"
                                             :label="eDrilling_Ops[item]"
                                          >
                                          </el-option>
                                       </el-select>
                                    </el-form-item>
                                    <el-form-item label="维度筛选:">
                                       <el-select
                                          v-model="state.exploreForm.dimensionFiltering.user"
                                          autocomplete="off"
                                          style="width: 186.4px"
                                          clearable
                                          @change="handleDimensionFilteringChange"
                                       >
                                          <el-option
                                             v-for="item in Object.keys(eDrilling_Ops)"
                                             :key="item"
                                             :value="parseInt(item)"
                                             :label="eDrilling_Ops[item]"
                                          >
                                          </el-option>
                                       </el-select>
                                       <el-select
                                          v-model="state.exploreForm.dimensionFiltering.unit"
                                          autocomplete="off"
                                          style="width: 126.4px; margin: 0 5px"
                                          clearable
                                       >
                                          <el-option
                                             v-for="item in Object.keys(eDimensionFilter_Ops)"
                                             :key="item"
                                             :value="parseInt(item)"
                                             :label="eDimensionFilter_Ops[item]"
                                          >
                                          </el-option>
                                       </el-select>
                                       <el-select v-model="state.resultList" autocomplete="off" style="width: 126.4px; margin-right: 5px" clearable>
                                          <el-option
                                             v-for="(item, index) in state.resultList"
                                             :key="index"
                                             :value="item.department"
                                             :label="item.department"
                                          >
                                          </el-option>
                                       </el-select>
                                       <el-button type="primary" @click="handleExplore" icon="ele-Search">查询</el-button>
                                 </el-col>
                                 <el-col :span="12" class="mb20" v-for="item in filterDimList" :key="item.id"
                                    ><el-form-item :label="`${item.title}:`" :prop="`${item.id}`">
                                       <el-input v-model="dialogFormValue[item.id]" @input="(val) => filterDimInput(val, item)"> </el-input>
                                    </el-form-item>
                                 </el-form>
                              </div>
                              <div class="w100 h-[550px]">
                                 <div ref="chartExplorationRef" class="w100 h100"></div>
                              </div>
                                 </el-col>
                              </el-row>
                           </el-form>
                           <div class="flex-auto mt-4">
                              <SummaryCom
                                 v-loading="queryLoading"
                                 ref="summaryComRef"
                                 :data="querySummaryData"
                                 :origin-data="{
                                    content: {
                                       origin: {
                                          summary: querySummaryData,
                                       },
                                    },
                                 }"
                              />
                              <!-- <RecordSet v-bind="recordSetProps" class="h-full" /> -->
                              <!-- <RecordSetTable v-bind="recordSetTableProps" class="h-full"/> -->
                           </div>
                        </div>
                     </el-tab-pane>
                     <el-tab-pane label="指标图谱" name="metricGraph" class="h-full">
                        <div class="h-full">
                           <TreeGraph v-if="graphData" :data="graphData" class="h-full" :maxCount="maxCount" /></div
                     ></el-tab-pane>
                  </el-tabs>
               </div>
               <div class="list_btn" @click="handleExitFlow">
@@ -133,10 +113,28 @@
               <div class="set-detail">
                  <el-divider />
                  <div class="section___vePzi">
                     <div class="item___txXyB" v-for="(item, index) in state.metricBasicInfo.visitNumData" :key="index">
                        <div class="item_name">{{ item.name }}:</div>
                     <div class="item___txXyB">
                        <div class="item_name">重要性:</div>
                        <div class="item_value">{{ eMetrics_Ops[state.metricBasicInfo.descriptionQuotaItems.metrics_important] }}</div>
                     </div>
                     <div class="item___txXyB">
                        <div class="item_name">所属领域:</div>
                        <div class="item_value">
                           {{ item.value }}
                           {{
                              state.metricBasicInfo.descriptionQuotaItems.metrics_type
                                 ? state.metricBasicInfo.descriptionQuotaItems.metrics_type
                                 : '-'
                           }}
                        </div>
                     </div>
                     <div class="item___txXyB">
                        <div class="item_name">描述:</div>
                        <div class="item_value">
                           {{
                              state.metricBasicInfo.descriptionQuotaItems.metrics_define
                                 ? state.metricBasicInfo.descriptionQuotaItems.metrics_define
                                 : '-'
                           }}
                        </div>
                     </div>
                  </div>
@@ -146,10 +144,24 @@
                        <i class="ywifont ywicon-gongzuozongjie w-[18px] h-[18px] !text-[18px]"></i>
                        <span>创建信息</span>
                     </div>
                     <div class="item___txXyB" v-for="(item, index) in state.metricBasicInfo.createInformation" :key="index">
                        <div class="item_name">{{ item.name }}:</div>
                     <div class="item___txXyB">
                        <div class="item_name">创建人:</div>
                        <div class="item_value">
                           {{ item.value }}
                           {{
                              state.metricBasicInfo.descriptionQuotaItems.create_user
                                 ? state.metricBasicInfo.descriptionQuotaItems.create_user
                                 : '-'
                           }}
                        </div>
                     </div>
                     <div class="item___txXyB">
                        <div class="item_name">创建时间:</div>
                        <div class="item_value">
                           {{
                              state.metricBasicInfo.descriptionQuotaItems.create_time
                                 ? state.metricBasicInfo.descriptionQuotaItems.create_time
                                 : '-'
                           }}
                        </div>
                     </div>
                  </div>
@@ -165,7 +177,7 @@
                              <div class="subTitle___zya5g">下钻维度</div>
                              <div class="ml-0 mt-[20px]">
                                 <div class="flex flex-wrap gap-[5px] items-center">
                                    <div v-for="item in state.metricBasicInfo.applicationInformation" :key="item.id">
                                    <div v-for="item in currentMetrics?.dimensions ?? []" :key="item.id">
                                       <el-tag :style="{ backgroundColor: 'e6f4ff', color: '#0958d9', borderColor: '#91caff' }">{{
                                          item.title
                                       }}</el-tag>
@@ -188,51 +200,32 @@
import { nextTick, onMounted, reactive, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import * as metricApi from '/@/api/metrics';
import TimeRange from '/@/components/chat/chatComponents/summaryCom/components/recordSet/components/TimeRange.vue';
import { formatTime, getDefaultPeriod } from '/@/utils/istation/common.js';
import { eMetrics_Ops } from '/@/views/types/metrics';
import { eDimensionFilter_Ops, eDrilling_Ops } from '/@/views/types/metrics/index';
import TreeGraph from '/@/components/graph/treeGraph/TreeGraph.vue';
import { FormRules } from 'element-plus/es/components/form/src/types';
import _, { debounce } from 'lodash';
import { computed } from 'vue';
import SummaryCom from './components/SummaryCom.vue';
import { chatMetricsJsonByPost } from '/@/api/metrics';
import { useCompRef } from '/@/utils/types';
import { OrgTreeItem } from '../agentGraph/types';
const defaultTime = ref<[Date, Date]>([new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)]);
const router = useRouter();
const route = useRoute();
// 定义变量内容
const state = reactive({
   metricInfo: {
      name: '',
      id: '',
   } as any,
   activeMetricName: 'basicInformation',
   descriptionQuotaItems: {} as any,
   metricBasicInfo: {
      visitNumData: [
         {
            name: '重要性',
            value: '',
         },
         {
            name: '所属模型',
            value: '',
         },
         {
            name: '描述',
            value: '',
         },
      ],
      createInformation: [
         {
            name: '创建人',
            value: 'admin',
         },
         {
            name: '创建时间',
            value: '2024-10-08 10:03:39',
         },
         {
            name: '更新时间',
            value: '2024-10-08 14:12:11',
         },
      ],
      applicationInformation: [],
   },
      descriptionQuotaItems: {},
   } as any,
   exploreForm: {
      dateRangeExplore: '' as any,
      dimensionDrilling: 0,
@@ -244,15 +237,19 @@
   },
   resultList: [
      {
         id: 1,
         department: 'HR',
      },
      {
         id: 2,
         department: 'marketing',
      },
      {
         id: 3,
         department: 'sales',
      },
      {
         id: 4,
         department: 'strategy',
      },
   ],
@@ -267,30 +264,23 @@
//#endregion
//#region ====================== 基础信息 ======================
const currentMetrics = ref(null);
const tableData = ref([]);
const getTableData = async (id) => {
   const res = await metricApi.getMetricNameListByPost();
   const data = res?.values ?? [];
   const filterData = data.filter((item) => item.id == id);
   state.descriptionQuotaItems = filterData[0];
   state.metricBasicInfo.visitNumData = [
      {
         name: '重要性',
         value: eMetrics_Ops[filterData[0].metrics_important],
      },
      {
         name: '所属模型',
         value: '-',
      },
      {
         name: '描述',
         value: filterData[0].metrics_define,
      },
   ];
   state.metricBasicInfo.applicationInformation = filterData[0].dimensions ?? [];
   state.metricBasicInfo.descriptionQuotaItems = filterData[0]; //左侧描述内容
   currentMetrics.value = filterData[0];
   filterDimList.value.forEach((item) => {
      if (!dialogFormValue.value) {
         dialogFormValue.value = {} as any;
      }
      dialogFormValue.value[item.id] = '';
   });
};
//#endregion
//#region ====================== 指标探索查询 ======================
//#region ====================== 指标图谱查询 ======================
// 时间限制
const disablesDate = (time) => {
   return time.getTime() > new Date().getTime();
@@ -425,10 +415,128 @@
      });
   }
   state.activeMetricName = val;
   if (val === 'metricGraph') {
      if (!graphData.value) {
         getGraphTreeData();
      }
   }
};
//#endregion
//#region ====================== 指标图谱 ======================
const filterDimList = computed(
   () => currentMetrics?.value?.dimensions ?? [].filter((item) => item.filter_type === 'str_eq' && item.type === '字符串')
);
const dialogFormRules = ref<FormRules>({
   title: [{ required: true, message: '请输入标题', trigger: 'blur' }],
   prompt: [{ required: true, message: '请输入提示词', trigger: 'blur' }],
});
const summaryComRef = useCompRef(SummaryCom);
const dialogFormValue = ref({
   rangValue: ['2024-10-21 00:00:00', '2024-10-23 23:59:59'],
   groupDimList: [],
});
const currentMetricsId = computed(() => router.currentRoute.value.query.id as string);
const querySummaryData = ref([]);
const queryLoading = ref(false);
/**
 * 按查询条件查找
 */
const query = async (isFirst: boolean) => {
   if (!currentMetricsId.value) return;
   const groupDimStr = dialogFormValue.value.groupDimList.join(',');
   const sendGroupDims = groupDimStr || undefined;
   queryLoading.value = true;
   const res = await chatMetricsJsonByPost(
      {
         metrics_id: currentMetricsId.value,
         start_time: dialogFormValue.value.rangValue[0],
         end_time: dialogFormValue.value.rangValue[1],
         group_dims: sendGroupDims,
         filter_dims: JSON.stringify(_.omit(dialogFormValue.value, ['groupDimList', 'rangValue'])),
      },
      {
         loading: false,
      }
   ).finally(() => {
      queryLoading.value = false;
   });
   querySummaryData.value = res?.summary ?? [];
   if (!isFirst) {
      nextTick(() => {
         nextTick(() => {
            summaryComRef.value.updateSummary();
         });
      });
   }
};
const debounceQuery = debounce(query, 600);
const filterDimInput = (val, dim) => {
   debounceQuery(false);
};
//#endregion
//#region ====================== 指标图谱 ======================
const maxCount = ref(null);
const graphData = ref(null);
const convertOrgTreeToTreeNode = (orgTreeData: OrgTreeItem) => {
   const treeData = {
      id: orgTreeData.treeId,
      label: orgTreeData.label,
      data: orgTreeData,
      children: orgTreeData.children?.length > 0 ? orgTreeData.children.map((item) => convertOrgTreeToTreeNode(item)) : [],
   };
   return treeData;
};
const getGraphTreeData = () => {
   if (!currentMetricsId.value) return;
   /** @description 维度数量 */
   let dimensionCount = 0;
   /** @description 指标数量 */
   let metricsCount = 1;
   const metricsTreeId = `metrics-${currentMetricsId.value}`;
   const dimensionList = currentMetrics.value.dimensions ?? [];
   dimensionCount = dimensionList.length;
   let logicTree: OrgTreeItem = {
      treeId: metricsTreeId,
      logicId: currentMetricsId.value,
      type: 'metrics',
      model: currentMetrics.value,
      get label() {
         return this.model.title;
      },
      level: 0,
      children: dimensionList.map((item) => {
         const dimensionTreeId = `${metricsTreeId}-dimension-${item.id}`;
         return {
            treeId: dimensionTreeId,
            logicId: item.id,
            type: 'dimension',
            model: item,
            get label() {
               return this.model.title;
            },
            level: 1,
         };
      }),
   };
   const resData = logicTree;
   maxCount.value = Math.max(dimensionCount, metricsCount);
   graphData.value = convertOrgTreeToTreeNode(resData);
};
//#endregion
onMounted(() => {
   const { id } = route.query;
   query(true);
   getTableData(id);
});
</script>