import React, { useEffect, useRef, useState } from 'react'; import { Form, Button, Modal, Steps, Input, Select, Radio, Switch, InputNumber, message, Result, Row, Col, Space, Tooltip, } from 'antd'; import { InfoCircleOutlined } from '@ant-design/icons'; import MetricMeasuresFormTable from './MetricMeasuresFormTable'; import { SENSITIVE_LEVEL_OPTIONS } from '../constant'; import { formLayout } from '@/components/FormHelper/utils'; import FormItemTitle from '@/components/FormHelper/FormItemTitle'; import styles from './style.less'; import { getMeasureListByModelId, getModelDetail } from '../service'; import DimensionAndMetricRelationModal from './DimensionAndMetricRelationModal'; import TableTitleTooltips from '../components/TableTitleTooltips'; import { creatExprMetric, updateExprMetric, mockMetricAlias, getMetricTags } from '../service'; import { ISemantic } from '../data'; import { history } from 'umi'; export type CreateFormProps = { datasourceId?: number; domainId: number; modelId: number; createModalVisible: boolean; metricItem: any; onCancel?: () => void; onSubmit?: (values: any) => void; }; const { Step } = Steps; const FormItem = Form.Item; const { TextArea } = Input; const { Option } = Select; const MetricInfoCreateForm: React.FC = ({ datasourceId, domainId, modelId, onCancel, createModalVisible, metricItem, onSubmit, }) => { const isEdit = !!metricItem?.id; const [currentStep, setCurrentStep] = useState(0); const formValRef = useRef({} as any); const [form] = Form.useForm(); const updateFormVal = (val: any) => { const formVal = { ...formValRef.current, ...val, }; formValRef.current = formVal; }; const [classMeasureList, setClassMeasureList] = useState([]); const [exprTypeParamsState, setExprTypeParamsState] = useState([]); const [exprSql, setExprSql] = useState(''); const [isPercentState, setIsPercentState] = useState(false); const [isDecimalState, setIsDecimalState] = useState(false); const [hasMeasuresState, setHasMeasuresState] = useState(true); const [llmLoading, setLlmLoading] = useState(false); const [tagOptions, setTagOptions] = useState<{ label: string; value: string }[]>([]); const [metricRelationModalOpenState, setMetricRelationModalOpenState] = useState(false); const [drillDownDimensions, setDrillDownDimensions] = useState< ISemantic.IDrillDownDimensionItem[] >(metricItem?.relateDimension?.drillDownDimensions || []); const forward = () => setCurrentStep(currentStep + 1); const backward = () => setCurrentStep(currentStep - 1); const queryClassMeasureList = async () => { // const { code, data } = await getMeasureListByModelId(modelId); const { code, data } = await getModelDetail({ modelId }); if (code === 200) { if (Array.isArray(data?.modelDetail?.measures)) { setClassMeasureList(data); if (datasourceId) { const hasMeasures = data.some( (item: ISemantic.IMeasure) => item.datasourceId === datasourceId, ); setHasMeasuresState(hasMeasures); } return; } } setClassMeasureList([]); }; useEffect(() => { queryClassMeasureList(); queryMetricTags(); }, []); const handleNext = async () => { const fieldsValue = await form.validateFields(); const submitForm = { ...formValRef.current, ...fieldsValue, typeParams: { expr: exprSql, measures: exprTypeParamsState, }, }; updateFormVal(submitForm); if (currentStep < 1) { forward(); } else { await saveMetric(submitForm); } }; const initData = () => { const { id, name, bizName, description, sensitiveLevel, typeParams: typeParams, dataFormat, dataFormatType, alias, tags, } = metricItem as any; const isPercent = dataFormatType === 'percent'; const isDecimal = dataFormatType === 'decimal'; const initValue = { id, name, bizName, sensitiveLevel, description, tags, // isPercent, dataFormatType: dataFormatType || '', alias: alias && alias.trim() ? alias.split(',') : [], dataFormat: dataFormat || { decimalPlaces: 2, needMultiply100: false, }, }; const editInitFormVal = { ...formValRef.current, ...initValue, }; updateFormVal(editInitFormVal); form.setFieldsValue(initValue); setExprTypeParamsState(typeParams.measures); setExprSql(typeParams.expr); setIsPercentState(isPercent); setIsDecimalState(isDecimal); }; useEffect(() => { if (isEdit) { initData(); } }, [metricItem]); const saveMetric = async (fieldsValue: any) => { const queryParams = { modelId: isEdit ? metricItem.modelId : modelId, relateDimension: { ...(metricItem?.relateDimension || {}), drillDownDimensions, }, ...fieldsValue, }; const { typeParams, alias, dataFormatType } = queryParams; queryParams.alias = Array.isArray(alias) ? alias.join(',') : ''; if (!typeParams?.expr) { message.error('请输入度量表达式'); return; } if (!dataFormatType) { delete queryParams.dataFormat; } if (!(Array.isArray(typeParams?.measures) && typeParams.measures.length > 0)) { message.error('请添加一个度量'); return; } let saveMetricQuery = creatExprMetric; if (queryParams.id) { saveMetricQuery = updateExprMetric; } const { code, msg } = await saveMetricQuery(queryParams); if (code === 200) { message.success('编辑指标成功'); onSubmit?.(queryParams); return; } message.error(msg); }; const generatorMetricAlias = async () => { setLlmLoading(true); const { code, data } = await mockMetricAlias({ ...metricItem }); const formAlias = form.getFieldValue('alias'); setLlmLoading(false); if (code === 200) { form.setFieldValue('alias', Array.from(new Set([...formAlias, ...data]))); } else { message.error('大语言模型解析异常'); } }; const queryMetricTags = async () => { const { code, data } = await getMetricTags(); if (code === 200) { // form.setFieldValue('alias', Array.from(new Set([...formAlias, ...data]))); setTagOptions( Array.isArray(data) ? data.map((tag: string) => { return { label: tag, value: tag }; }) : [], ); } else { message.error('获取指标标签失败'); } }; const renderContent = () => { if (currentStep === 1) { return ( { setExprTypeParamsState([...typeParams]); }} onSqlChange={(sql: string) => { setExprSql(sql); }} /> ); } return ( <>

在录入指标时,请务必详细填写指标口径。口径描述对于理解指标的含义、计算方法和使用场景至关重要。一个清晰、准确的口径描述可以帮助其他用户更好地理解和使用该指标,避免因为误解而导致错误的数据分析和决策。在填写口径时,建议包括以下信息:

1. 指标的计算方法:详细说明指标是如何计算的,包括涉及的公式、计算步骤等。

2. 数据来源:描述指标所依赖的数据来源,包括数据表、字段等信息。

3. 使用场景:说明该指标适用于哪些业务场景,以及如何在这些场景中使用该指标。

4. 任何其他相关信息:例如数据更新频率、数据质量要求等。

请确保口径描述清晰、简洁且易于理解,以便其他用户能够快速掌握指标的核心要点。

} /> } rules={[{ required: true, message: '请输入业务口径' }]} >