mirror of
https://github.com/tencentmusic/supersonic.git
synced 2025-12-20 06:34:55 +00:00
[improvement][headless-fe] Revamped the interaction for semantic modeling routing and successfully implemented the switching between dimension and dataset management.
This commit is contained in:
@@ -95,6 +95,12 @@ const ROUTES = [
|
|||||||
path: '/model/dataset/:domainId/:datasetId',
|
path: '/model/dataset/:domainId/:datasetId',
|
||||||
component: './SemanticModel/View/components/Detail',
|
component: './SemanticModel/View/components/Detail',
|
||||||
envEnableList: [ENV_KEY.SEMANTIC],
|
envEnableList: [ENV_KEY.SEMANTIC],
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/model/dataset/:domainId/:datasetId/:menuKey',
|
||||||
|
component: './SemanticModel/View/components/Detail',
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/model/metric/:domainId/:modelId/:metricId',
|
path: '/model/metric/:domainId/:modelId/:metricId',
|
||||||
@@ -107,6 +113,17 @@ const ROUTES = [
|
|||||||
// },
|
// },
|
||||||
// ],
|
// ],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/model/dimension/:domainId/:modelId/:dimensionId',
|
||||||
|
component: './SemanticModel/Dimension/Detail',
|
||||||
|
envEnableList: [ENV_KEY.SEMANTIC],
|
||||||
|
// routes: [
|
||||||
|
// {
|
||||||
|
// path: '/model/manager/:domainId/:modelId/:menuKey',
|
||||||
|
// component: './SemanticModel/ModelManager',
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
import { message } from 'antd';
|
||||||
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
|
import { useParams, useModel, Helmet } from '@umijs/max';
|
||||||
|
import { BASE_TITLE } from '@/common/constants';
|
||||||
|
import { ISemantic } from '../data';
|
||||||
|
import { getDimensionList } from '../service';
|
||||||
|
import DetailContainer from '@/pages/SemanticModel/components/DetailContainer';
|
||||||
|
import DetailSider from '@/pages/SemanticModel/components/DetailContainer/DetailSider';
|
||||||
|
import { ProjectOutlined, ConsoleSqlOutlined } from '@ant-design/icons';
|
||||||
|
import DimensionInfoForm from '../components/DimensionInfoForm';
|
||||||
|
import DetailFormWrapper from '@/pages/SemanticModel/components/DetailContainer/DetailFormWrapper';
|
||||||
|
|
||||||
|
type Props = Record<string, any>;
|
||||||
|
|
||||||
|
const DataSetDetail: React.FC<Props> = () => {
|
||||||
|
const settingList = [
|
||||||
|
{
|
||||||
|
icon: <ProjectOutlined />,
|
||||||
|
key: 'basic',
|
||||||
|
text: '基本信息',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const params: any = useParams();
|
||||||
|
const detailId = params.dimensionId;
|
||||||
|
const modelId = params.modelId;
|
||||||
|
const domainId = params.domainId;
|
||||||
|
const menuKey = params.menuKey;
|
||||||
|
const [detailData, setDetailData] = useState<ISemantic.IDimensionItem>();
|
||||||
|
const dimensionModel = useModel('SemanticModel.dimensionData');
|
||||||
|
const { setSelectDimension } = dimensionModel;
|
||||||
|
const [activeMenu, setActiveMenu] = useState<any>(() => {
|
||||||
|
if (menuKey) {
|
||||||
|
const target = settingList.find((item) => item.key === menuKey);
|
||||||
|
if (target) {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return settingList[0];
|
||||||
|
});
|
||||||
|
const detailFormRef = useRef<any>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
setSelectDimension(undefined);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!detailId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
queryDetailData(detailId);
|
||||||
|
}, [detailId]);
|
||||||
|
|
||||||
|
const queryDetailData = async (id: number) => {
|
||||||
|
const { code, data, msg } = await getDimensionList({ ids: [id] });
|
||||||
|
if (code === 200) {
|
||||||
|
const target = data?.list?.[0];
|
||||||
|
setDetailData(target);
|
||||||
|
setSelectDimension(target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
message.error(msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Helmet title={`[数据集]${detailData?.name}-${BASE_TITLE}`} />
|
||||||
|
<DetailContainer
|
||||||
|
siderNode={
|
||||||
|
<DetailSider
|
||||||
|
menuKey={activeMenu.key}
|
||||||
|
menuList={settingList}
|
||||||
|
detailData={detailData}
|
||||||
|
onMenuKeyChange={(key: string, menu) => {
|
||||||
|
setActiveMenu(menu);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
containerNode={
|
||||||
|
<DetailFormWrapper
|
||||||
|
currentMenu={activeMenu}
|
||||||
|
onSave={() => {
|
||||||
|
detailFormRef.current.onSave();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DimensionInfoForm
|
||||||
|
ref={detailFormRef}
|
||||||
|
modelId={modelId}
|
||||||
|
domainId={domainId}
|
||||||
|
dimensionItem={detailData}
|
||||||
|
/>
|
||||||
|
</DetailFormWrapper>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DataSetDetail;
|
||||||
@@ -33,6 +33,9 @@ const MetricDetail: React.FC<Props> = () => {
|
|||||||
}, [metricId]);
|
}, [metricId]);
|
||||||
|
|
||||||
const queryMetricData = async (metricId: string) => {
|
const queryMetricData = async (metricId: string) => {
|
||||||
|
if (!metricId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const { code, data, msg } = await getMetricData(metricId);
|
const { code, data, msg } = await getMetricData(metricId);
|
||||||
if (code === 200) {
|
if (code === 200) {
|
||||||
setMetircData({ ...data });
|
setMetircData({ ...data });
|
||||||
@@ -104,7 +107,9 @@ const MetricDetail: React.FC<Props> = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Helmet title={`[指标]${metircData?.name}-${BASE_TITLE}`} />
|
<Helmet
|
||||||
|
title={`${metircData?.id ? `[指标]${metircData?.name}-${BASE_TITLE}` : '新建指标'}`}
|
||||||
|
/>
|
||||||
<div className={styles.metricDetailWrapper}>
|
<div className={styles.metricDetailWrapper}>
|
||||||
<div className={styles.metricDetail}>
|
<div className={styles.metricDetail}>
|
||||||
<div className={styles.siderContainer}>
|
<div className={styles.siderContainer}>
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ type Props = Record<string, any>;
|
|||||||
|
|
||||||
const MetricDetail: React.FC<Props> = () => {
|
const MetricDetail: React.FC<Props> = () => {
|
||||||
const params: any = useParams();
|
const params: any = useParams();
|
||||||
const metricId = params.metricId;
|
const metricId = +params.metricId;
|
||||||
|
const modelId = +params.modelId;
|
||||||
|
const domainId = +params.domainId;
|
||||||
const [metircData, setMetircData] = useState<ISemantic.IMetricItem>();
|
const [metircData, setMetircData] = useState<ISemantic.IMetricItem>();
|
||||||
const metricModel = useModel('SemanticModel.metricData');
|
const metricModel = useModel('SemanticModel.metricData');
|
||||||
const { setSelectMetric } = metricModel;
|
const { setSelectMetric } = metricModel;
|
||||||
@@ -33,7 +35,10 @@ const MetricDetail: React.FC<Props> = () => {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const queryMetricData = async (metricId: string) => {
|
const queryMetricData = async (metricId: number) => {
|
||||||
|
if (!metricId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const { code, data, msg } = await getMetricData(metricId);
|
const { code, data, msg } = await getMetricData(metricId);
|
||||||
if (code === 200) {
|
if (code === 200) {
|
||||||
setMetircData({ ...data });
|
setMetircData({ ...data });
|
||||||
@@ -58,7 +63,11 @@ const MetricDetail: React.FC<Props> = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Helmet title={`[指标]${metircData?.name}-${BASE_TITLE}`} />
|
<Helmet
|
||||||
|
title={`${
|
||||||
|
metircData?.id ? `[指标]${metircData?.name}-${BASE_TITLE}` : `新建指标-${BASE_TITLE}`
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
<DetailContainer
|
<DetailContainer
|
||||||
siderNode={
|
siderNode={
|
||||||
<DetailSider
|
<DetailSider
|
||||||
@@ -70,7 +79,14 @@ const MetricDetail: React.FC<Props> = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
containerNode={<MetricInfoCreateForm settingKey={settingKey} metricItem={metircData} />}
|
containerNode={
|
||||||
|
<MetricInfoCreateForm
|
||||||
|
settingKey={settingKey}
|
||||||
|
metricItem={metircData}
|
||||||
|
modelId={metircData?.modelId || modelId}
|
||||||
|
domainId={metircData?.domainId || domainId}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -37,9 +37,12 @@ import { createMetric, updateMetric, mockMetricAlias, getMetricTags } from '../.
|
|||||||
import { MetricSettingKey, MetricSettingWording } from '../constants';
|
import { MetricSettingKey, MetricSettingWording } from '../constants';
|
||||||
import { ISemantic } from '../../data';
|
import { ISemantic } from '../../data';
|
||||||
import { history } from '@umijs/max';
|
import { history } from '@umijs/max';
|
||||||
|
import { toDomainList, toModelList } from '@/pages/SemanticModel/utils';
|
||||||
import globalStyles from '@/global.less';
|
import globalStyles from '@/global.less';
|
||||||
|
|
||||||
export type CreateFormProps = {
|
export type CreateFormProps = {
|
||||||
|
modelId: number;
|
||||||
|
domainId: number;
|
||||||
datasourceId?: number;
|
datasourceId?: number;
|
||||||
metricItem: any;
|
metricItem: any;
|
||||||
settingKey: MetricSettingKey;
|
settingKey: MetricSettingKey;
|
||||||
@@ -58,6 +61,8 @@ const queryParamsTypeParamsKey = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const MetricInfoCreateForm: React.FC<CreateFormProps> = ({
|
const MetricInfoCreateForm: React.FC<CreateFormProps> = ({
|
||||||
|
modelId,
|
||||||
|
domainId,
|
||||||
datasourceId,
|
datasourceId,
|
||||||
onCancel,
|
onCancel,
|
||||||
settingKey,
|
settingKey,
|
||||||
@@ -65,8 +70,6 @@ const MetricInfoCreateForm: React.FC<CreateFormProps> = ({
|
|||||||
onSubmit,
|
onSubmit,
|
||||||
}) => {
|
}) => {
|
||||||
const isEdit = !!metricItem?.id;
|
const isEdit = !!metricItem?.id;
|
||||||
const domainId = metricItem?.domainId;
|
|
||||||
const modelId = metricItem?.modelId;
|
|
||||||
const formValRef = useRef({} as any);
|
const formValRef = useRef({} as any);
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const updateFormVal = (val: any) => {
|
const updateFormVal = (val: any) => {
|
||||||
@@ -381,6 +384,9 @@ const MetricInfoCreateForm: React.FC<CreateFormProps> = ({
|
|||||||
}
|
}
|
||||||
message.success('编辑指标成功');
|
message.success('编辑指标成功');
|
||||||
onSubmit?.(queryParams);
|
onSubmit?.(queryParams);
|
||||||
|
if (!isEdit) {
|
||||||
|
toModelList(domainId, modelId!, 'metric');
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
message.error(msg);
|
message.error(msg);
|
||||||
@@ -480,10 +486,11 @@ const MetricInfoCreateForm: React.FC<CreateFormProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const renderContent = () => {
|
const renderContent = () => {
|
||||||
if (settingKey === MetricSettingKey.SQL_CONFIG) {
|
return (
|
||||||
return (
|
<>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
display: settingKey === MetricSettingKey.SQL_CONFIG ? 'block' : 'none',
|
||||||
marginLeft: '-24px',
|
marginLeft: '-24px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -607,211 +614,211 @@ const MetricInfoCreateForm: React.FC<CreateFormProps> = ({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
<div style={{ display: settingKey === MetricSettingKey.BASIC ? 'block' : 'none' }}>
|
||||||
<>
|
<FormItem hidden={true} name="id" label="ID">
|
||||||
<FormItem hidden={true} name="id" label="ID">
|
<Input placeholder="id" />
|
||||||
<Input placeholder="id" />
|
</FormItem>
|
||||||
</FormItem>
|
|
||||||
<Row gutter={20}>
|
|
||||||
<Col span={12}>
|
|
||||||
<FormItem
|
|
||||||
name="name"
|
|
||||||
label="指标名称"
|
|
||||||
rules={[{ required: true, message: '请输入指标名称' }]}
|
|
||||||
>
|
|
||||||
<Input placeholder="名称不可重复" />
|
|
||||||
</FormItem>
|
|
||||||
</Col>
|
|
||||||
<Col span={12}>
|
|
||||||
<FormItem
|
|
||||||
name="bizName"
|
|
||||||
label="英文名称"
|
|
||||||
rules={[{ required: true, message: '请输入英文名称' }]}
|
|
||||||
>
|
|
||||||
<Input placeholder="名称不可重复" disabled={isEdit} />
|
|
||||||
</FormItem>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<Row gutter={20}>
|
|
||||||
<Col span={12}>
|
|
||||||
<FormItem
|
|
||||||
name="sensitiveLevel"
|
|
||||||
label="敏感度"
|
|
||||||
rules={[{ required: true, message: '请选择敏感度' }]}
|
|
||||||
>
|
|
||||||
<Select placeholder="请选择敏感度">
|
|
||||||
{SENSITIVE_LEVEL_OPTIONS.map((item) => (
|
|
||||||
<Option key={item.value} value={item.value}>
|
|
||||||
{item.label}
|
|
||||||
</Option>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
</FormItem>
|
|
||||||
</Col>
|
|
||||||
<Col span={12}>
|
|
||||||
<FormItem name="classifications" label="分类">
|
|
||||||
<Select
|
|
||||||
mode="tags"
|
|
||||||
placeholder="支持手动输入及选择"
|
|
||||||
tokenSeparators={[',']}
|
|
||||||
maxTagCount={9}
|
|
||||||
options={tagOptions}
|
|
||||||
/>
|
|
||||||
</FormItem>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
|
|
||||||
<FormItem
|
|
||||||
name="description"
|
|
||||||
label={
|
|
||||||
<TableTitleTooltips
|
|
||||||
title="业务口径"
|
|
||||||
overlayInnerStyle={{ width: 600 }}
|
|
||||||
tooltips={
|
|
||||||
<>
|
|
||||||
<p>
|
|
||||||
在录入指标时,请务必详细填写指标口径。口径描述对于理解指标的含义、计算方法和使用场景至关重要。一个清晰、准确的口径描述可以帮助其他用户更好地理解和使用该指标,避免因为误解而导致错误的数据分析和决策。在填写口径时,建议包括以下信息:
|
|
||||||
</p>
|
|
||||||
<p>1. 指标的计算方法:详细说明指标是如何计算的,包括涉及的公式、计算步骤等。</p>
|
|
||||||
<p>2. 数据来源:描述指标所依赖的数据来源,包括数据表、字段等信息。</p>
|
|
||||||
<p>3. 使用场景:说明该指标适用于哪些业务场景,以及如何在这些场景中使用该指标。</p>
|
|
||||||
<p>4. 任何其他相关信息:例如数据更新频率、数据质量要求等。</p>
|
|
||||||
<p>
|
|
||||||
请确保口径描述清晰、简洁且易于理解,以便其他用户能够快速掌握指标的核心要点。
|
|
||||||
</p>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
rules={[{ required: true, message: '请输入业务口径' }]}
|
|
||||||
>
|
|
||||||
<TextArea placeholder="请输入业务口径" style={{ minHeight: 173 }} />
|
|
||||||
</FormItem>
|
|
||||||
|
|
||||||
<FormItem label="别名">
|
|
||||||
<Row gutter={20}>
|
<Row gutter={20}>
|
||||||
<Col flex="1 1 200px">
|
<Col span={12}>
|
||||||
<FormItem name="alias" noStyle>
|
<FormItem
|
||||||
|
name="name"
|
||||||
|
label="指标名称"
|
||||||
|
rules={[{ required: true, message: '请输入指标名称' }]}
|
||||||
|
>
|
||||||
|
<Input placeholder="名称不可重复" />
|
||||||
|
</FormItem>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<FormItem
|
||||||
|
name="bizName"
|
||||||
|
label="英文名称"
|
||||||
|
rules={[{ required: true, message: '请输入英文名称' }]}
|
||||||
|
>
|
||||||
|
<Input placeholder="名称不可重复" disabled={isEdit} />
|
||||||
|
</FormItem>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row gutter={20}>
|
||||||
|
<Col span={12}>
|
||||||
|
<FormItem
|
||||||
|
name="sensitiveLevel"
|
||||||
|
label="敏感度"
|
||||||
|
rules={[{ required: true, message: '请选择敏感度' }]}
|
||||||
|
>
|
||||||
|
<Select placeholder="请选择敏感度">
|
||||||
|
{SENSITIVE_LEVEL_OPTIONS.map((item) => (
|
||||||
|
<Option key={item.value} value={item.value}>
|
||||||
|
{item.label}
|
||||||
|
</Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormItem>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<FormItem name="classifications" label="分类">
|
||||||
<Select
|
<Select
|
||||||
style={{ maxWidth: 500 }}
|
|
||||||
mode="tags"
|
mode="tags"
|
||||||
placeholder="输入别名后回车确认,多别名输入、复制粘贴支持英文逗号自动分隔"
|
placeholder="支持手动输入及选择"
|
||||||
tokenSeparators={[',']}
|
tokenSeparators={[',']}
|
||||||
maxTagCount={9}
|
maxTagCount={9}
|
||||||
|
options={tagOptions}
|
||||||
/>
|
/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</Col>
|
</Col>
|
||||||
{isEdit && (
|
|
||||||
<Col flex="0 1 75px">
|
|
||||||
<Tooltip title="智能填充将根据指标相关信息,使用大语言模型获取指标别名">
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
loading={llmLoading}
|
|
||||||
style={{ top: '5px' }}
|
|
||||||
onClick={() => {
|
|
||||||
generatorMetricAlias();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
智能填充
|
|
||||||
</Button>
|
|
||||||
</Tooltip>
|
|
||||||
</Col>
|
|
||||||
)}
|
|
||||||
</Row>
|
</Row>
|
||||||
</FormItem>
|
|
||||||
<Divider />
|
|
||||||
<FormItem
|
|
||||||
name="isTag"
|
|
||||||
valuePropName="checked"
|
|
||||||
hidden={!!!process.env.SHOW_TAG}
|
|
||||||
getValueFromEvent={(value) => {
|
|
||||||
return value === true ? 1 : 0;
|
|
||||||
}}
|
|
||||||
getValueProps={(value) => {
|
|
||||||
return {
|
|
||||||
checked: value === 1,
|
|
||||||
};
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Row gutter={20}>
|
|
||||||
<Col flex="1 1 200px">
|
|
||||||
<FormItemTitle
|
|
||||||
title={`设为标签`}
|
|
||||||
subTitle={`如果勾选,代表取值都是一种'标签',可用作对实体的圈选`}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
|
|
||||||
<Col flex="0 1 75px">
|
|
||||||
<Switch />
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<Divider />
|
|
||||||
</FormItem>
|
|
||||||
|
|
||||||
<FormItem>
|
|
||||||
<Row gutter={20}>
|
|
||||||
<Col flex="1 1 200px">
|
|
||||||
<FormItemTitle
|
|
||||||
title={'下钻维度配置'}
|
|
||||||
subTitle={'配置下钻维度后,将可以在指标卡中进行下钻'}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
|
|
||||||
<Col flex="0 1 75px">
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
onClick={() => {
|
|
||||||
setMetricRelationModalOpenState(true);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
设 置
|
|
||||||
</Button>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</FormItem>
|
|
||||||
<Divider />
|
|
||||||
<FormItem label={<FormItemTitle title={'数据格式化'} />} name="dataFormatType">
|
|
||||||
<Radio.Group buttonStyle="solid" size="middle">
|
|
||||||
<Radio.Button value="">默认</Radio.Button>
|
|
||||||
<Radio.Button value="decimal">小数</Radio.Button>
|
|
||||||
<Radio.Button value="percent">百分比</Radio.Button>
|
|
||||||
</Radio.Group>
|
|
||||||
</FormItem>
|
|
||||||
|
|
||||||
{(isPercentState || isDecimalState) && (
|
|
||||||
<FormItem
|
<FormItem
|
||||||
|
name="description"
|
||||||
label={
|
label={
|
||||||
<FormItemTitle
|
<TableTitleTooltips
|
||||||
title={'小数位数'}
|
title="业务口径"
|
||||||
subTitle={`对小数位数进行设置,如保留两位,0.021252 -> 0.02${
|
overlayInnerStyle={{ width: 600 }}
|
||||||
isPercentState ? '%' : ''
|
tooltips={
|
||||||
}`}
|
<>
|
||||||
|
<p>
|
||||||
|
在录入指标时,请务必详细填写指标口径。口径描述对于理解指标的含义、计算方法和使用场景至关重要。一个清晰、准确的口径描述可以帮助其他用户更好地理解和使用该指标,避免因为误解而导致错误的数据分析和决策。在填写口径时,建议包括以下信息:
|
||||||
|
</p>
|
||||||
|
<p>1. 指标的计算方法:详细说明指标是如何计算的,包括涉及的公式、计算步骤等。</p>
|
||||||
|
<p>2. 数据来源:描述指标所依赖的数据来源,包括数据表、字段等信息。</p>
|
||||||
|
<p>
|
||||||
|
3. 使用场景:说明该指标适用于哪些业务场景,以及如何在这些场景中使用该指标。
|
||||||
|
</p>
|
||||||
|
<p>4. 任何其他相关信息:例如数据更新频率、数据质量要求等。</p>
|
||||||
|
<p>
|
||||||
|
请确保口径描述清晰、简洁且易于理解,以便其他用户能够快速掌握指标的核心要点。
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
name={['dataFormat', 'decimalPlaces']}
|
rules={[{ required: true, message: '请输入业务口径' }]}
|
||||||
>
|
>
|
||||||
<InputNumber placeholder="请输入需要保留小数位数" style={{ width: '300px' }} />
|
<TextArea placeholder="请输入业务口径" style={{ minHeight: 173 }} />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
|
||||||
{isPercentState && (
|
<FormItem label="别名">
|
||||||
<>
|
<Row gutter={20}>
|
||||||
|
<Col flex="1 1 200px">
|
||||||
|
<FormItem name="alias" noStyle>
|
||||||
|
<Select
|
||||||
|
style={{ maxWidth: 500 }}
|
||||||
|
mode="tags"
|
||||||
|
placeholder="输入别名后回车确认,多别名输入、复制粘贴支持英文逗号自动分隔"
|
||||||
|
tokenSeparators={[',']}
|
||||||
|
maxTagCount={9}
|
||||||
|
/>
|
||||||
|
</FormItem>
|
||||||
|
</Col>
|
||||||
|
{isEdit && (
|
||||||
|
<Col flex="0 1 75px">
|
||||||
|
<Tooltip title="智能填充将根据指标相关信息,使用大语言模型获取指标别名">
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
loading={llmLoading}
|
||||||
|
style={{ top: '5px' }}
|
||||||
|
onClick={() => {
|
||||||
|
generatorMetricAlias();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
智能填充
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</Col>
|
||||||
|
)}
|
||||||
|
</Row>
|
||||||
|
</FormItem>
|
||||||
|
<Divider />
|
||||||
|
<FormItem
|
||||||
|
name="isTag"
|
||||||
|
valuePropName="checked"
|
||||||
|
hidden={!!!process.env.SHOW_TAG}
|
||||||
|
getValueFromEvent={(value) => {
|
||||||
|
return value === true ? 1 : 0;
|
||||||
|
}}
|
||||||
|
getValueProps={(value) => {
|
||||||
|
return {
|
||||||
|
checked: value === 1,
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Row gutter={20}>
|
||||||
|
<Col flex="1 1 200px">
|
||||||
|
<FormItemTitle
|
||||||
|
title={`设为标签`}
|
||||||
|
subTitle={`如果勾选,代表取值都是一种'标签',可用作对实体的圈选`}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
<Col flex="0 1 75px">
|
||||||
|
<Switch />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Divider />
|
||||||
|
</FormItem>
|
||||||
|
|
||||||
|
<FormItem>
|
||||||
|
<Row gutter={20}>
|
||||||
|
<Col flex="1 1 200px">
|
||||||
|
<FormItemTitle
|
||||||
|
title={'下钻维度配置'}
|
||||||
|
subTitle={'配置下钻维度后,将可以在指标卡中进行下钻'}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
<Col flex="0 1 75px">
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
onClick={() => {
|
||||||
|
setMetricRelationModalOpenState(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
设 置
|
||||||
|
</Button>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</FormItem>
|
||||||
|
<Divider />
|
||||||
|
<FormItem label={<FormItemTitle title={'数据格式化'} />} name="dataFormatType">
|
||||||
|
<Radio.Group buttonStyle="solid" size="middle">
|
||||||
|
<Radio.Button value="">默认</Radio.Button>
|
||||||
|
<Radio.Button value="decimal">小数</Radio.Button>
|
||||||
|
<Radio.Button value="percent">百分比</Radio.Button>
|
||||||
|
</Radio.Group>
|
||||||
|
</FormItem>
|
||||||
|
|
||||||
|
{(isPercentState || isDecimalState) && (
|
||||||
<FormItem
|
<FormItem
|
||||||
label={
|
label={
|
||||||
<FormItemTitle
|
<FormItemTitle
|
||||||
title={'原始值是否乘以100'}
|
title={'小数位数'}
|
||||||
subTitle={'如 原始值0.001 ->展示值0.1% '}
|
subTitle={`对小数位数进行设置,如保留两位,0.021252 -> 0.02${
|
||||||
|
isPercentState ? '%' : ''
|
||||||
|
}`}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
name={['dataFormat', 'needMultiply100']}
|
name={['dataFormat', 'decimalPlaces']}
|
||||||
valuePropName="checked"
|
|
||||||
>
|
>
|
||||||
<Switch />
|
<InputNumber placeholder="请输入需要保留小数位数" style={{ width: '300px' }} />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</>
|
)}
|
||||||
)}
|
{isPercentState && (
|
||||||
|
<>
|
||||||
|
<FormItem
|
||||||
|
label={
|
||||||
|
<FormItemTitle
|
||||||
|
title={'原始值是否乘以100'}
|
||||||
|
subTitle={'如 原始值0.001 ->展示值0.1% '}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
name={['dataFormat', 'needMultiply100']}
|
||||||
|
valuePropName="checked"
|
||||||
|
>
|
||||||
|
<Switch />
|
||||||
|
</FormItem>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -892,15 +899,13 @@ const MetricInfoCreateForm: React.FC<CreateFormProps> = ({
|
|||||||
<Result
|
<Result
|
||||||
style={{ background: '#fff' }}
|
style={{ background: '#fff' }}
|
||||||
status="warning"
|
status="warning"
|
||||||
subTitle="当前数据源缺少度量,无法创建指标。请前往数据源配置中,将字段设置为度量"
|
subTitle="当前数据模型缺少度量,无法创建指标。请前往模型配置中,将字段设置为度量"
|
||||||
extra={
|
extra={
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
key="console"
|
key="console"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
history.replace(
|
toDomainList(domainId, 'menuKey');
|
||||||
`/model/domain/manager/${domainId}/${modelId || metricItem?.modelId}/dataSource`,
|
|
||||||
);
|
|
||||||
onCancel?.();
|
onCancel?.();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ const ModelManager: React.FC<Props> = ({}) => {
|
|||||||
|
|
||||||
const initModelConfig = () => {
|
const initModelConfig = () => {
|
||||||
const currentMenuKey = menuKey === defaultTabKey ? '' : menuKey;
|
const currentMenuKey = menuKey === defaultTabKey ? '' : menuKey;
|
||||||
toModelList(selectDomainId, selectModelId, currentMenuKey);
|
toModelList(selectDomainId, selectModelId!, currentMenuKey);
|
||||||
setActiveKey(currentMenuKey);
|
setActiveKey(currentMenuKey);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ const ModelManager: React.FC<Props> = ({}) => {
|
|||||||
modelList={modelList}
|
modelList={modelList}
|
||||||
onMenuChange={(menuKey) => {
|
onMenuChange={(menuKey) => {
|
||||||
setActiveKey(menuKey);
|
setActiveKey(menuKey);
|
||||||
toModelList(selectDomainId, selectModelId, menuKey);
|
toModelList(selectDomainId, selectModelId!, menuKey);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
import { Tabs, Breadcrumb, Space, Radio } from 'antd';
|
import { Tabs, Breadcrumb, Space, Radio } from 'antd';
|
||||||
import React, { useRef, useEffect, useState } from 'react';
|
import React, { useRef, useEffect, useState } from 'react';
|
||||||
import { history, useModel } from '@umijs/max';
|
import { history, useModel } from '@umijs/max';
|
||||||
import { HomeOutlined, FundViewOutlined } from '@ant-design/icons';
|
import {
|
||||||
|
HomeOutlined,
|
||||||
|
FundViewOutlined,
|
||||||
|
BarChartOutlined,
|
||||||
|
LineChartOutlined,
|
||||||
|
} from '@ant-design/icons';
|
||||||
import styles from './components/style.less';
|
import styles from './components/style.less';
|
||||||
import { toDomainList, toModelList } from '@/pages/SemanticModel/utils';
|
import { toDomainList, toModelList } from '@/pages/SemanticModel/utils';
|
||||||
|
|
||||||
@@ -9,8 +14,10 @@ const PageBreadcrumb: React.FC = () => {
|
|||||||
const domainModel = useModel('SemanticModel.domainData');
|
const domainModel = useModel('SemanticModel.domainData');
|
||||||
const modelModel = useModel('SemanticModel.modelData');
|
const modelModel = useModel('SemanticModel.modelData');
|
||||||
const metricModel = useModel('SemanticModel.metricData');
|
const metricModel = useModel('SemanticModel.metricData');
|
||||||
const { selectDomainId, selectDomainName, selectDomain: domainData } = domainModel;
|
const dimensionModel = useModel('SemanticModel.dimensionData');
|
||||||
|
const { selectDomainId, selectDomainName, selectDataSet, setSelectDataSet } = domainModel;
|
||||||
const { selectModelId, selectModelName, setSelectModel } = modelModel;
|
const { selectModelId, selectModelName, setSelectModel } = modelModel;
|
||||||
|
const { selectDimension, setSelectDimension } = dimensionModel;
|
||||||
|
|
||||||
const { selectMetric, setSelectMetric } = metricModel;
|
const { selectMetric, setSelectMetric } = metricModel;
|
||||||
|
|
||||||
@@ -20,6 +27,9 @@ const PageBreadcrumb: React.FC = () => {
|
|||||||
<Space
|
<Space
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setSelectModel(undefined);
|
setSelectModel(undefined);
|
||||||
|
setSelectDimension(undefined);
|
||||||
|
setSelectMetric(undefined);
|
||||||
|
setSelectDataSet(undefined);
|
||||||
toDomainList(selectDomainId, 'overview');
|
toDomainList(selectDomainId, 'overview');
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -30,6 +40,23 @@ const PageBreadcrumb: React.FC = () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (selectDataSet) {
|
||||||
|
items.push(
|
||||||
|
{
|
||||||
|
type: 'separator',
|
||||||
|
separator: '/',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: (
|
||||||
|
<Space onClick={() => {}}>
|
||||||
|
<FundViewOutlined style={{ position: 'relative', top: '2px' }} />
|
||||||
|
<span>{selectDataSet.name}</span>
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (selectModelName) {
|
if (selectModelName) {
|
||||||
items.push(
|
items.push(
|
||||||
{
|
{
|
||||||
@@ -40,8 +67,13 @@ const PageBreadcrumb: React.FC = () => {
|
|||||||
title: (
|
title: (
|
||||||
<Space
|
<Space
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
setSelectDimension(undefined);
|
||||||
setSelectMetric(undefined);
|
setSelectMetric(undefined);
|
||||||
toModelList(selectDomainId, selectModelId);
|
if (selectDimension) {
|
||||||
|
toModelList(selectDomainId, selectModelId!, 'dimension');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
toModelList(selectDomainId, selectModelId!, 'metric');
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FundViewOutlined style={{ position: 'relative', top: '2px' }} />
|
<FundViewOutlined style={{ position: 'relative', top: '2px' }} />
|
||||||
@@ -52,6 +84,23 @@ const PageBreadcrumb: React.FC = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (selectDimension) {
|
||||||
|
items.push(
|
||||||
|
{
|
||||||
|
type: 'separator',
|
||||||
|
separator: '/',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: (
|
||||||
|
<Space onClick={() => {}}>
|
||||||
|
<BarChartOutlined style={{ position: 'relative', top: '2px' }} />
|
||||||
|
<span>{selectDimension.name}</span>
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (selectMetric?.name) {
|
if (selectMetric?.name) {
|
||||||
items.push(
|
items.push(
|
||||||
{
|
{
|
||||||
@@ -61,7 +110,7 @@ const PageBreadcrumb: React.FC = () => {
|
|||||||
{
|
{
|
||||||
title: selectMetric?.name ? (
|
title: selectMetric?.name ? (
|
||||||
<Space>
|
<Space>
|
||||||
<FundViewOutlined style={{ position: 'relative', top: '2px' }} />
|
<LineChartOutlined style={{ position: 'relative', top: '2px' }} />
|
||||||
<span>{selectMetric.name}</span>
|
<span>{selectMetric.name}</span>
|
||||||
</Space>
|
</Space>
|
||||||
) : undefined,
|
) : undefined,
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ const DataSetTable: React.FC<Props> = ({ disabledEdit = false }) => {
|
|||||||
return (
|
return (
|
||||||
<a
|
<a
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
toDatasetEditPage(record.domainId, record.id);
|
toDatasetEditPage(record.domainId, record.id, 'relation');
|
||||||
// setEditFormStep(1);
|
// setEditFormStep(1);
|
||||||
// setViewItem(record);
|
// setViewItem(record);
|
||||||
// setCreateDataSourceModalOpen(true);
|
// setCreateDataSourceModalOpen(true);
|
||||||
@@ -145,9 +145,10 @@ const DataSetTable: React.FC<Props> = ({ disabledEdit = false }) => {
|
|||||||
<a
|
<a
|
||||||
key="metricEditBtn"
|
key="metricEditBtn"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setEditFormStep(0);
|
toDatasetEditPage(record.domainId, record.id);
|
||||||
setViewItem(record);
|
// setEditFormStep(0);
|
||||||
setCreateDataSourceModalOpen(true);
|
// setViewItem(record);
|
||||||
|
// setCreateDataSourceModalOpen(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
编辑
|
编辑
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React, { useState, useEffect, useRef } from 'react';
|
import React, { useState, useEffect, useRef, forwardRef, useImperativeHandle } from 'react';
|
||||||
import { Form, Button, Modal, Input, Select, Steps, Spin, Space } from 'antd';
|
import { Form, Input, Select, Spin, Space } from 'antd';
|
||||||
|
import type { Ref } from 'react';
|
||||||
import styles from '../../components/style.less';
|
import styles from '../../components/style.less';
|
||||||
import { message } from 'antd';
|
import { message } from 'antd';
|
||||||
import { formLayout } from '@/components/FormHelper/utils';
|
import { formLayout } from '@/components/FormHelper/utils';
|
||||||
@@ -8,224 +9,153 @@ import { ISemantic } from '../../data';
|
|||||||
import FormItemTitle from '@/components/FormHelper/FormItemTitle';
|
import FormItemTitle from '@/components/FormHelper/FormItemTitle';
|
||||||
import SelectTMEPerson from '@/components/SelectTMEPerson';
|
import SelectTMEPerson from '@/components/SelectTMEPerson';
|
||||||
import ViewModelConfigTransfer from './ViewModelConfigTransfer';
|
import ViewModelConfigTransfer from './ViewModelConfigTransfer';
|
||||||
import type { FormInstance } from 'antd';
|
|
||||||
|
|
||||||
const FormItem = Form.Item;
|
const FormItem = Form.Item;
|
||||||
|
|
||||||
export type ModelCreateFormModalProps = {
|
export type ModelCreateFormModalProps = {
|
||||||
// step: number;
|
|
||||||
form: FormInstance;
|
|
||||||
activeKey: string;
|
activeKey: string;
|
||||||
domainId: number;
|
domainId: number;
|
||||||
viewItem: any;
|
datasetItem: any;
|
||||||
modelList: ISemantic.IModelItem[];
|
modelList: ISemantic.IModelItem[];
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
onSubmit: (values: any) => void;
|
onSubmit: (values: any) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const DatasetCreateForm: React.FC<ModelCreateFormModalProps> = ({
|
const DatasetCreateForm: React.FC<ModelCreateFormModalProps> = forwardRef(
|
||||||
form,
|
(
|
||||||
activeKey,
|
{ activeKey, datasetItem, domainId, onCancel, onSubmit, modelList }: ModelCreateFormModalProps,
|
||||||
viewItem,
|
ref: Ref<any>,
|
||||||
domainId,
|
) => {
|
||||||
onCancel,
|
const [saveLoading, setSaveLoading] = useState<boolean>(false);
|
||||||
onSubmit,
|
const [dimensionLoading, setDimensionLoading] = useState<boolean>(false);
|
||||||
modelList,
|
const [selectedModelItem, setSelectedModelItem] = useState<ISemantic.IModelItem | undefined>(
|
||||||
}) => {
|
modelList[0],
|
||||||
const stepWidth: Record<string, number> = {
|
);
|
||||||
'0': 800,
|
const [form] = Form.useForm();
|
||||||
'1': 1200,
|
const configTableRef = useRef<any>();
|
||||||
'2': 800,
|
|
||||||
};
|
|
||||||
// const [currentStep, setCurrentStep] = useState();
|
|
||||||
|
|
||||||
const [formVals, setFormVals] = useState<ISemantic.IModelItem>({
|
useImperativeHandle(ref, () => ({
|
||||||
...viewItem,
|
onSave: () => {
|
||||||
currentModel: modelList[0]?.id,
|
return handleConfirm();
|
||||||
});
|
|
||||||
|
|
||||||
const [queryType, setQueryType] = useState<string>('METRIC');
|
|
||||||
|
|
||||||
const [saveLoading, setSaveLoading] = useState<boolean>(false);
|
|
||||||
const [dimensionLoading, setDimensionLoading] = useState<boolean>(false);
|
|
||||||
// const [modalWidth, setModalWidth] = useState<number>(stepWidth[`${currentStep}`]);
|
|
||||||
const [selectedModelItem, setSelectedModelItem] = useState<ISemantic.IModelItem | undefined>(
|
|
||||||
modelList[0],
|
|
||||||
);
|
|
||||||
// const [form] = Form.useForm();
|
|
||||||
const configTableRef = useRef<any>();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
form.setFieldsValue({
|
|
||||||
...viewItem,
|
|
||||||
});
|
|
||||||
// setQueryType(viewItem?.queryType);
|
|
||||||
}, [viewItem]);
|
|
||||||
|
|
||||||
const [dimensionList, setDimensionList] = useState<ISemantic.IDimensionItem[]>();
|
|
||||||
const [metricList, setMetricList] = useState<ISemantic.IMetricItem[]>();
|
|
||||||
// const [tagList, setTagList] = useState<ISemantic.ITagItem[]>();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
console.log(selectedModelItem, 'selectedModelItemselectedModelItem');
|
|
||||||
if (selectedModelItem?.id) {
|
|
||||||
queryDimensionList(selectedModelItem.id);
|
|
||||||
queryMetricList(selectedModelItem.id);
|
|
||||||
// queryTagList(selectedModelItem.id);
|
|
||||||
}
|
|
||||||
}, [selectedModelItem]);
|
|
||||||
|
|
||||||
const queryDimensionList = async (modelId: number) => {
|
|
||||||
setDimensionLoading(true);
|
|
||||||
const { code, data, msg } = await getDimensionList({ modelId });
|
|
||||||
setDimensionLoading(false);
|
|
||||||
if (code === 200 && Array.isArray(data?.list)) {
|
|
||||||
setDimensionList(data.list);
|
|
||||||
} else {
|
|
||||||
message.error(msg);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const queryMetricList = async (modelId: number) => {
|
|
||||||
const { code, data, msg } = await queryMetric({ modelId });
|
|
||||||
if (code === 200 && Array.isArray(data?.list)) {
|
|
||||||
setMetricList(data.list);
|
|
||||||
} else {
|
|
||||||
message.error(msg);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleConfirm = async () => {
|
|
||||||
const fieldsValue = await form.validateFields();
|
|
||||||
const viewModelConfigsMap = configTableRef?.current.getViewModelConfigs() || {};
|
|
||||||
|
|
||||||
const queryData: ISemantic.IModelItem = {
|
|
||||||
...formVals,
|
|
||||||
...fieldsValue,
|
|
||||||
queryType,
|
|
||||||
dataSetDetail: {
|
|
||||||
dataSetModelConfigs: Object.values(viewModelConfigsMap),
|
|
||||||
},
|
},
|
||||||
domainId,
|
}));
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (Array.isArray(modelList) || !selectedModelItem) {
|
||||||
|
setSelectedModelItem(modelList[0]);
|
||||||
|
}
|
||||||
|
}, [modelList]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
form.setFieldsValue({
|
||||||
|
...datasetItem,
|
||||||
|
});
|
||||||
|
}, [datasetItem]);
|
||||||
|
|
||||||
|
const [dimensionList, setDimensionList] = useState<ISemantic.IDimensionItem[]>();
|
||||||
|
const [metricList, setMetricList] = useState<ISemantic.IMetricItem[]>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedModelItem?.id) {
|
||||||
|
queryDimensionList(selectedModelItem.id);
|
||||||
|
queryMetricList(selectedModelItem.id);
|
||||||
|
}
|
||||||
|
}, [selectedModelItem]);
|
||||||
|
|
||||||
|
const queryDimensionList = async (modelId: number) => {
|
||||||
|
setDimensionLoading(true);
|
||||||
|
const { code, data, msg } = await getDimensionList({ modelId });
|
||||||
|
setDimensionLoading(false);
|
||||||
|
if (code === 200 && Array.isArray(data?.list)) {
|
||||||
|
setDimensionList(data.list);
|
||||||
|
} else {
|
||||||
|
message.error(msg);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
setFormVals(queryData);
|
|
||||||
setSaveLoading(true);
|
|
||||||
const { code, msg } = await (!queryData.id ? createView : updateView)(queryData);
|
|
||||||
setSaveLoading(false);
|
|
||||||
if (code === 200) {
|
|
||||||
onSubmit?.(queryData);
|
|
||||||
} else {
|
|
||||||
message.error(msg);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// const forward = () => {
|
const queryMetricList = async (modelId: number) => {
|
||||||
// setModalWidth(stepWidth[`${currentStep + 1}`]);
|
const { code, data, msg } = await queryMetric({ modelId });
|
||||||
// setCurrentStep(currentStep + 1);
|
if (code === 200 && Array.isArray(data?.list)) {
|
||||||
// };
|
setMetricList(data.list);
|
||||||
// const backward = () => {
|
} else {
|
||||||
// setModalWidth(stepWidth[`${currentStep - 1}`]);
|
message.error(msg);
|
||||||
// setCurrentStep(currentStep - 1);
|
}
|
||||||
// };
|
};
|
||||||
|
|
||||||
// const handleNext = async () => {
|
const handleConfirm = async () => {
|
||||||
// await form.validateFields();
|
const fieldsValue = await form.validateFields();
|
||||||
// forward();
|
const viewModelConfigsMap = configTableRef?.current.getViewModelConfigs() || {};
|
||||||
// };
|
|
||||||
|
|
||||||
// const renderFooter = () => {
|
const queryData: ISemantic.IModelItem = {
|
||||||
// if (currentStep === 1) {
|
...datasetItem,
|
||||||
// return (
|
...fieldsValue,
|
||||||
// <>
|
dataSetDetail: {
|
||||||
// <Button style={{ float: 'left' }} onClick={backward}>
|
dataSetModelConfigs: Object.values(viewModelConfigsMap),
|
||||||
// 上一步
|
},
|
||||||
// </Button>
|
domainId,
|
||||||
// <Button
|
};
|
||||||
// type="primary"
|
setSaveLoading(true);
|
||||||
// loading={saveLoading}
|
const { code, msg } = await (!queryData.id ? createView : updateView)(queryData);
|
||||||
// onClick={() => {
|
setSaveLoading(false);
|
||||||
// handleConfirm();
|
if (code === 200) {
|
||||||
// }}
|
onSubmit?.(queryData);
|
||||||
// >
|
} else {
|
||||||
// 保 存
|
message.error(msg);
|
||||||
// </Button>
|
}
|
||||||
// </>
|
};
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// return (
|
|
||||||
// <>
|
|
||||||
// <Button onClick={onCancel}>取消</Button>
|
|
||||||
// <Button type="primary" onClick={handleNext}>
|
|
||||||
// 下一步
|
|
||||||
// </Button>
|
|
||||||
// <Button
|
|
||||||
// type="primary"
|
|
||||||
// loading={saveLoading}
|
|
||||||
// onClick={() => {
|
|
||||||
// handleConfirm();
|
|
||||||
// }}
|
|
||||||
// >
|
|
||||||
// 保 存
|
|
||||||
// </Button>
|
|
||||||
// </>
|
|
||||||
// );
|
|
||||||
// };
|
|
||||||
|
|
||||||
const renderContent = () => {
|
const renderContent = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div style={{ display: activeKey === 'relation' ? 'block' : 'none' }}>
|
<div style={{ display: activeKey === 'relation' ? 'block' : 'none' }}>
|
||||||
<Spin spinning={dimensionLoading}>
|
<Spin spinning={dimensionLoading}>
|
||||||
<ViewModelConfigTransfer
|
<ViewModelConfigTransfer
|
||||||
key={queryType}
|
toolbarSolt={
|
||||||
queryType={queryType}
|
<Space>
|
||||||
toolbarSolt={
|
<span>切换模型: </span>
|
||||||
<Space>
|
<Select
|
||||||
<span>切换模型: </span>
|
style={{
|
||||||
<Select
|
minWidth: 150,
|
||||||
style={{
|
textAlign: 'left',
|
||||||
minWidth: 150,
|
}}
|
||||||
textAlign: 'left',
|
value={selectedModelItem?.id}
|
||||||
}}
|
placeholder="请选择模型,获取当前模型下指标维度信息"
|
||||||
value={selectedModelItem?.id}
|
onChange={(val) => {
|
||||||
placeholder="请选择模型,获取当前模型下指标维度信息"
|
setDimensionList(undefined);
|
||||||
onChange={(val) => {
|
setMetricList(undefined);
|
||||||
console.log(val, 211111111);
|
const modelItem = modelList.find((item) => item.id === val);
|
||||||
setDimensionList(undefined);
|
setSelectedModelItem(modelItem);
|
||||||
setMetricList(undefined);
|
}}
|
||||||
const modelItem = modelList.find((item) => item.id === val);
|
options={modelList.map((item) => {
|
||||||
setSelectedModelItem(modelItem);
|
return { label: item.name, value: item.id };
|
||||||
}}
|
})}
|
||||||
options={modelList.map((item) => {
|
/>
|
||||||
return { label: item.name, value: item.id };
|
</Space>
|
||||||
})}
|
}
|
||||||
/>
|
dimensionList={dimensionList}
|
||||||
</Space>
|
metricList={metricList}
|
||||||
}
|
modelItem={selectedModelItem}
|
||||||
dimensionList={dimensionList}
|
viewItem={datasetItem}
|
||||||
metricList={metricList}
|
ref={configTableRef}
|
||||||
modelItem={selectedModelItem}
|
/>
|
||||||
viewItem={viewItem}
|
</Spin>
|
||||||
ref={configTableRef}
|
</div>
|
||||||
/>
|
<div style={{ display: activeKey === 'basic' ? 'block' : 'none' }}>
|
||||||
</Spin>
|
<FormItem
|
||||||
</div>
|
name="name"
|
||||||
<div style={{ display: activeKey === 'basic' ? 'block' : 'none' }}>
|
label="数据集名称"
|
||||||
<FormItem
|
rules={[{ required: true, message: '请输入数据集名称!' }]}
|
||||||
name="name"
|
>
|
||||||
label="数据集名称"
|
<Input placeholder="数据集名称不可重复" />
|
||||||
rules={[{ required: true, message: '请输入数据集名称!' }]}
|
</FormItem>
|
||||||
>
|
<FormItem
|
||||||
<Input placeholder="数据集名称不可重复" />
|
name="bizName"
|
||||||
</FormItem>
|
label="数据集英文名称"
|
||||||
<FormItem
|
rules={[{ required: true, message: '请输入数据集英文名称!' }]}
|
||||||
name="bizName"
|
>
|
||||||
label="数据集英文名称"
|
<Input placeholder="请输入数据集英文名称" />
|
||||||
rules={[{ required: true, message: '请输入数据集英文名称!' }]}
|
</FormItem>
|
||||||
>
|
{/* <FormItem
|
||||||
<Input placeholder="请输入数据集英文名称" />
|
|
||||||
</FormItem>
|
|
||||||
{/* <FormItem
|
|
||||||
name="alias"
|
name="alias"
|
||||||
label="别名"
|
label="别名"
|
||||||
getValueFromEvent={(value) => {
|
getValueFromEvent={(value) => {
|
||||||
@@ -244,46 +174,29 @@ const DatasetCreateForm: React.FC<ModelCreateFormModalProps> = ({
|
|||||||
maxTagCount={9}
|
maxTagCount={9}
|
||||||
/>
|
/>
|
||||||
</FormItem> */}
|
</FormItem> */}
|
||||||
<FormItem name="admins" label={<FormItemTitle title={'责任人'} />}>
|
<FormItem name="admins" label={<FormItemTitle title={'责任人'} />}>
|
||||||
<SelectTMEPerson placeholder="请邀请团队成员" />
|
<SelectTMEPerson placeholder="请邀请团队成员" />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem name="description" label="数据集描述">
|
<FormItem name="description" label="数据集描述">
|
||||||
<Input.TextArea placeholder="数据集描述" />
|
<Input.TextArea placeholder="数据集描述" />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Form
|
||||||
|
{...formLayout}
|
||||||
|
form={form}
|
||||||
|
onValuesChange={(value, values) => {}}
|
||||||
|
className={styles.form}
|
||||||
|
>
|
||||||
|
{renderContent()}
|
||||||
|
</Form>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
},
|
||||||
|
);
|
||||||
return (
|
|
||||||
// <Modal
|
|
||||||
// width={modalWidth}
|
|
||||||
// destroyOnClose
|
|
||||||
// title={'数据集信息'}
|
|
||||||
// open={true}
|
|
||||||
// maskClosable={false}
|
|
||||||
// footer={renderFooter()}
|
|
||||||
// onCancel={onCancel}
|
|
||||||
// >
|
|
||||||
<>
|
|
||||||
{/* <Steps style={{ marginBottom: 28 }} size="small" current={currentStep}>
|
|
||||||
<Step title="基本信息" />
|
|
||||||
<Step title="关联信息" />
|
|
||||||
</Steps> */}
|
|
||||||
<Form
|
|
||||||
{...formLayout}
|
|
||||||
form={form}
|
|
||||||
initialValues={{
|
|
||||||
...formVals,
|
|
||||||
}}
|
|
||||||
onValuesChange={(value, values) => {}}
|
|
||||||
className={styles.form}
|
|
||||||
>
|
|
||||||
{renderContent()}
|
|
||||||
</Form>
|
|
||||||
</>
|
|
||||||
// </Modal>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DatasetCreateForm;
|
export default DatasetCreateForm;
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
import { message, Form } from 'antd';
|
import { message, Form } from 'antd';
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
import { getMetricData } from '../../service';
|
|
||||||
import { useParams, useModel, Helmet } from '@umijs/max';
|
import { useParams, useModel, Helmet } from '@umijs/max';
|
||||||
import { BASE_TITLE } from '@/common/constants';
|
import { BASE_TITLE } from '@/common/constants';
|
||||||
import { ISemantic } from '../../data';
|
import { ISemantic } from '../../data';
|
||||||
import { createView, updateView, getAllModelByDomainId, getDataSetDetail } from '../../service';
|
import { getAllModelByDomainId, getDataSetDetail } from '../../service';
|
||||||
import DetailContainer from '@/pages/SemanticModel/components/DetailContainer';
|
import DetailContainer from '@/pages/SemanticModel/components/DetailContainer';
|
||||||
import DetailSider from '@/pages/SemanticModel/components/DetailContainer/DetailSider';
|
import DetailSider from '@/pages/SemanticModel/components/DetailContainer/DetailSider';
|
||||||
import { ProjectOutlined, ConsoleSqlOutlined } from '@ant-design/icons';
|
import { ProjectOutlined, ConsoleSqlOutlined } from '@ant-design/icons';
|
||||||
import DatasetCreateForm from './DatasetCreateForm';
|
import DatasetCreateForm from './DatasetCreateForm';
|
||||||
import DetailFormWrapper from '@/pages/SemanticModel/components/DetailContainer/DetailFormWrapper';
|
import DetailFormWrapper from '@/pages/SemanticModel/components/DetailContainer/DetailFormWrapper';
|
||||||
// import { MetricSettingKey, MetricSettingWording } from './constants';
|
|
||||||
|
|
||||||
type Props = Record<string, any>;
|
type Props = Record<string, any>;
|
||||||
|
|
||||||
@@ -29,16 +27,28 @@ const DataSetDetail: React.FC<Props> = () => {
|
|||||||
];
|
];
|
||||||
const params: any = useParams();
|
const params: any = useParams();
|
||||||
const detailId = params.datasetId;
|
const detailId = params.datasetId;
|
||||||
const [detailData, setDetailData] = useState<ISemantic.IMetricItem>();
|
const menuKey = params.menuKey;
|
||||||
|
const [detailData, setDetailData] = useState<ISemantic.IDatasetItem>();
|
||||||
const domainModel = useModel('SemanticModel.domainData');
|
const domainModel = useModel('SemanticModel.domainData');
|
||||||
const modelModel = useModel('SemanticModel.modelData');
|
const { selectDomainId, setSelectDataSet } = domainModel;
|
||||||
const { modelList } = modelModel;
|
const [modelList, setModelList] = useState<ISemantic.IModelItem[]>([]);
|
||||||
const { selectDomainId } = domainModel;
|
const [activeMenu, setActiveMenu] = useState<any>(() => {
|
||||||
const [settingKey, setSettingKey] = useState<string>();
|
if (menuKey) {
|
||||||
// const [modelList, setModelList] = useState<ISemantic.IModelItem[]>([]);
|
const target = settingList.find((item) => item.key === menuKey);
|
||||||
const [activeMenu, setActiveMenu] = useState<any>(settingList[0]);
|
if (target) {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const [form] = Form.useForm();
|
return settingList[0];
|
||||||
|
});
|
||||||
|
const detailFormRef = useRef<any>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
setSelectDataSet(undefined);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!detailId) {
|
if (!detailId) {
|
||||||
@@ -47,26 +57,27 @@ const DataSetDetail: React.FC<Props> = () => {
|
|||||||
queryDetailData(detailId);
|
queryDetailData(detailId);
|
||||||
}, [detailId]);
|
}, [detailId]);
|
||||||
|
|
||||||
// useEffect(() => {
|
useEffect(() => {
|
||||||
// if (!selectDomainId) {
|
if (!selectDomainId) {
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
// queryDomainAllModel();
|
queryDomainAllModel();
|
||||||
// }, [selectDomainId]);
|
}, [selectDomainId]);
|
||||||
|
|
||||||
// const queryDomainAllModel = async () => {
|
const queryDomainAllModel = async () => {
|
||||||
// const { code, data, msg } = await getAllModelByDomainId(selectDomainId);
|
const { code, data, msg } = await getAllModelByDomainId(selectDomainId);
|
||||||
// if (code === 200) {
|
if (code === 200) {
|
||||||
// setModelList(data);
|
setModelList(data);
|
||||||
// } else {
|
} else {
|
||||||
// message.error(msg);
|
message.error(msg);
|
||||||
// }
|
}
|
||||||
// };
|
};
|
||||||
|
|
||||||
const queryDetailData = async (id: number) => {
|
const queryDetailData = async (id: number) => {
|
||||||
const { code, data, msg } = await getDataSetDetail(id);
|
const { code, data, msg } = await getDataSetDetail(id);
|
||||||
if (code === 200) {
|
if (code === 200) {
|
||||||
setDetailData({ ...data });
|
setDetailData(data);
|
||||||
|
setSelectDataSet(data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
message.error(msg);
|
message.error(msg);
|
||||||
@@ -78,11 +89,11 @@ const DataSetDetail: React.FC<Props> = () => {
|
|||||||
<DetailContainer
|
<DetailContainer
|
||||||
siderNode={
|
siderNode={
|
||||||
<DetailSider
|
<DetailSider
|
||||||
menuKey={'basic'}
|
menuKey={activeMenu.key}
|
||||||
menuList={settingList}
|
menuList={settingList}
|
||||||
detailData={detailData}
|
detailData={detailData}
|
||||||
onMenuKeyChange={(key: string, menu) => {
|
onMenuKeyChange={(key: string, menu) => {
|
||||||
setSettingKey(key);
|
// setSettingKey(key);
|
||||||
setActiveMenu(menu);
|
setActiveMenu(menu);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -91,22 +102,15 @@ const DataSetDetail: React.FC<Props> = () => {
|
|||||||
<DetailFormWrapper
|
<DetailFormWrapper
|
||||||
currentMenu={activeMenu}
|
currentMenu={activeMenu}
|
||||||
onSave={() => {
|
onSave={() => {
|
||||||
console.log(form.getFieldsValue());
|
detailFormRef.current.onSave();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DatasetCreateForm
|
<DatasetCreateForm
|
||||||
form={form}
|
ref={detailFormRef}
|
||||||
activeKey={activeMenu.key}
|
activeKey={activeMenu.key}
|
||||||
domainId={selectDomainId}
|
domainId={selectDomainId}
|
||||||
viewItem={detailData}
|
datasetItem={detailData}
|
||||||
modelList={modelList}
|
modelList={modelList}
|
||||||
onSubmit={() => {
|
|
||||||
// queryDataSetList();
|
|
||||||
// setCreateDataSourceModalOpen(false);
|
|
||||||
}}
|
|
||||||
onCancel={() => {
|
|
||||||
// setCreateDataSourceModalOpen(false);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</DetailFormWrapper>
|
</DetailFormWrapper>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,7 +165,6 @@ const ViewCreateFormModal: React.FC<ModelCreateFormModalProps> = ({
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderContent = () => {
|
const renderContent = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ const ViewModelConfigTransfer: React.FC<Props> = forwardRef(
|
|||||||
setSelectedTransferKeys(transferKeys);
|
setSelectedTransferKeys(transferKeys);
|
||||||
setViewModelConfigsMap(viewConfigMap);
|
setViewModelConfigsMap(viewConfigMap);
|
||||||
}
|
}
|
||||||
}, [queryType]);
|
}, [queryType, viewItem]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (queryType !== TransType.METRIC) {
|
if (queryType !== TransType.METRIC) {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { ActionType, ProColumns } from '@ant-design/pro-components';
|
|||||||
import { ProTable } from '@ant-design/pro-components';
|
import { ProTable } from '@ant-design/pro-components';
|
||||||
import { message, Button, Space, Popconfirm, Input, Tag, Select } from 'antd';
|
import { message, Button, Space, Popconfirm, Input, Tag, Select } from 'antd';
|
||||||
import React, { useRef, useState, useEffect } from 'react';
|
import React, { useRef, useState, useEffect } from 'react';
|
||||||
import { useModel } from '@umijs/max';
|
import { useModel, history } from '@umijs/max';
|
||||||
import { StatusEnum, SemanticNodeType } from '../enum';
|
import { StatusEnum, SemanticNodeType } from '../enum';
|
||||||
import { SENSITIVE_LEVEL_ENUM, SENSITIVE_LEVEL_OPTIONS, TAG_DEFINE_TYPE } from '../constant';
|
import { SENSITIVE_LEVEL_ENUM, SENSITIVE_LEVEL_OPTIONS, TAG_DEFINE_TYPE } from '../constant';
|
||||||
import {
|
import {
|
||||||
@@ -19,6 +19,7 @@ import TableHeaderFilter from '@/components/TableHeaderFilter';
|
|||||||
import BatchCtrlDropDownButton from '@/components/BatchCtrlDropDownButton';
|
import BatchCtrlDropDownButton from '@/components/BatchCtrlDropDownButton';
|
||||||
import { ColumnsConfig } from './TableColumnRender';
|
import { ColumnsConfig } from './TableColumnRender';
|
||||||
import BatchSensitiveLevelModal from '@/components/BatchCtrlDropDownButton/BatchSensitiveLevelModal';
|
import BatchSensitiveLevelModal from '@/components/BatchCtrlDropDownButton/BatchSensitiveLevelModal';
|
||||||
|
import { toDimensionEditPage } from '@/pages/SemanticModel/utils';
|
||||||
import styles from './style.less';
|
import styles from './style.less';
|
||||||
|
|
||||||
type Props = {};
|
type Props = {};
|
||||||
@@ -80,6 +81,9 @@ const ClassDimensionTable: React.FC<Props> = ({}) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const queryDataSourceList = async () => {
|
const queryDataSourceList = async () => {
|
||||||
|
if (!domainId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const { code, data, msg } = await getModelList(domainId);
|
const { code, data, msg } = await getModelList(domainId);
|
||||||
if (code === 200) {
|
if (code === 200) {
|
||||||
setDataSourceList(data);
|
setDataSourceList(data);
|
||||||
@@ -94,7 +98,7 @@ const ClassDimensionTable: React.FC<Props> = ({}) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
queryDataSourceList();
|
queryDataSourceList();
|
||||||
}, [modelId]);
|
}, [domainId]);
|
||||||
|
|
||||||
const queryBatchUpdateStatus = async (ids: React.Key[], status: StatusEnum) => {
|
const queryBatchUpdateStatus = async (ids: React.Key[], status: StatusEnum) => {
|
||||||
if (Array.isArray(ids) && ids.length === 0) {
|
if (Array.isArray(ids) && ids.length === 0) {
|
||||||
@@ -137,7 +141,17 @@ const ClassDimensionTable: React.FC<Props> = ({}) => {
|
|||||||
message.error(msg);
|
message.error(msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
const columnsConfig = ColumnsConfig();
|
// const columnsConfig = ColumnsConfig();
|
||||||
|
const columnsConfig = ColumnsConfig({
|
||||||
|
indicatorInfo: {
|
||||||
|
url: '/model/dimension/:domainId/:modelId/:indicatorId',
|
||||||
|
onNameClick: (record) => {
|
||||||
|
const { id } = record;
|
||||||
|
toDimensionEditPage(domainId, modelId!, id);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const columns: ProColumns[] = [
|
const columns: ProColumns[] = [
|
||||||
{
|
{
|
||||||
@@ -216,8 +230,10 @@ const ClassDimensionTable: React.FC<Props> = ({}) => {
|
|||||||
key="dimensionEditBtn"
|
key="dimensionEditBtn"
|
||||||
type="link"
|
type="link"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setDimensionItem(record);
|
// setDimensionItem(record);
|
||||||
setCreateModalVisible(true);
|
// setCreateModalVisible(true);
|
||||||
|
const { id } = record;
|
||||||
|
toDimensionEditPage(domainId, modelId!, id);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
编辑
|
编辑
|
||||||
@@ -423,8 +439,9 @@ const ClassDimensionTable: React.FC<Props> = ({}) => {
|
|||||||
key="create"
|
key="create"
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setDimensionItem(undefined);
|
toDimensionEditPage(domainId, modelId!, 0);
|
||||||
setCreateModalVisible(true);
|
// setDimensionItem(undefined);
|
||||||
|
// setCreateModalVisible(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
创建维度
|
创建维度
|
||||||
|
|||||||
@@ -146,8 +146,8 @@ const ClassMetricTable: React.FC<Props> = ({ onEmptyMetricData }) => {
|
|||||||
const columnsConfig = ColumnsConfig({
|
const columnsConfig = ColumnsConfig({
|
||||||
indicatorInfo: {
|
indicatorInfo: {
|
||||||
url: '/model/metric/:domainId/:modelId/:indicatorId',
|
url: '/model/metric/:domainId/:modelId/:indicatorId',
|
||||||
onNameClick: (record: ISemantic.IMetricItem) => {
|
onNameClick: (record) => {
|
||||||
setSelectMetric(record);
|
setSelectMetric(record as ISemantic.IMetricItem);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -460,8 +460,9 @@ const ClassMetricTable: React.FC<Props> = ({ onEmptyMetricData }) => {
|
|||||||
key="create"
|
key="create"
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setMetricItem(undefined);
|
toMetricEditPage(selectDomainId, modelId!, 0);
|
||||||
setCreateModalVisible(true);
|
// setMetricItem(undefined);
|
||||||
|
// setCreateModalVisible(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
创建指标
|
创建指标
|
||||||
|
|||||||
@@ -35,7 +35,12 @@ const DetailSider: React.FC<Props> = ({ detailData, menuList, menuKey, onMenuKey
|
|||||||
<div className={styles.title}>
|
<div className={styles.title}>
|
||||||
<div className={styles.name}>
|
<div className={styles.name}>
|
||||||
<Space>
|
<Space>
|
||||||
<IndicatorStar indicatorId={detailData?.id} initState={detailData?.isCollect} />
|
{detailData?.isCollect !== undefined ? (
|
||||||
|
<IndicatorStar indicatorId={detailData?.id} initState={detailData?.isCollect} />
|
||||||
|
) : (
|
||||||
|
<div style={{ width: 15 }}></div>
|
||||||
|
)}
|
||||||
|
|
||||||
{detailData?.name}
|
{detailData?.name}
|
||||||
{detailData?.hasAdminRes && (
|
{detailData?.hasAdminRes && (
|
||||||
<span
|
<span
|
||||||
@@ -94,28 +99,31 @@ const DetailSider: React.FC<Props> = ({ detailData, menuList, menuKey, onMenuKey
|
|||||||
</Space>
|
</Space>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.item}>
|
{detailData?.modelName && (
|
||||||
<span className={styles.itemLable}>所属模型: </span>
|
<div className={styles.item}>
|
||||||
<span className={styles.itemValue}>
|
<span className={styles.itemLable}>所属模型: </span>
|
||||||
<Space>
|
<span className={styles.itemValue}>
|
||||||
<Tag icon={<PartitionOutlined />} color="#3b5999">
|
<Space>
|
||||||
{detailData?.modelName || '模型名为空'}
|
<Tag icon={<PartitionOutlined />} color="#3b5999">
|
||||||
</Tag>
|
{detailData?.modelName || '模型名为空'}
|
||||||
{detailData?.hasAdminRes && (
|
</Tag>
|
||||||
<span
|
{detailData?.hasAdminRes && (
|
||||||
className={styles.gotoMetricListIcon}
|
<span
|
||||||
onClick={() => {
|
className={styles.gotoMetricListIcon}
|
||||||
toDomainList(detailData.domainId, 'overview');
|
onClick={() => {
|
||||||
}}
|
toDomainList(detailData.domainId, 'overview');
|
||||||
>
|
}}
|
||||||
<Tooltip title="前往模型设置页">
|
>
|
||||||
<ExportOutlined />
|
<Tooltip title="前往模型设置页">
|
||||||
</Tooltip>
|
<ExportOutlined />
|
||||||
</span>
|
</Tooltip>
|
||||||
)}
|
</span>
|
||||||
</Space>
|
)}
|
||||||
</span>
|
</Space>
|
||||||
</div>
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className={styles.item}>
|
<div className={styles.item}>
|
||||||
<span className={styles.itemLable}>创建人: </span>
|
<span className={styles.itemLable}>创建人: </span>
|
||||||
<span className={styles.itemValue}>{detailData?.createdBy}</span>
|
<span className={styles.itemValue}>{detailData?.createdBy}</span>
|
||||||
|
|||||||
@@ -9,13 +9,13 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
.tabContainer {
|
.tabContainer {
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
min-height: calc(100vh - 78px);
|
min-height: calc(100vh - 105px);
|
||||||
width: calc(100vw - 350px);
|
width: calc(100vw - 350px);
|
||||||
background-color: #fafafb;
|
background-color: #fafafb;
|
||||||
}
|
}
|
||||||
.siderContainer {
|
.siderContainer {
|
||||||
width: 350px;
|
width: 320px;
|
||||||
min-height: calc(100vh - 78px);
|
min-height: calc(100vh - 105px);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
padding: 12px 0 12px 12px;
|
padding: 12px 0 12px 12px;
|
||||||
}
|
}
|
||||||
@@ -27,13 +27,16 @@
|
|||||||
|
|
||||||
|
|
||||||
.DetailInfoSider {
|
.DetailInfoSider {
|
||||||
padding: 20px;
|
padding: 10px;
|
||||||
color: #344767;
|
color: #344767;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border: 1px solid #e6ebf1;
|
border: 1px solid #e6ebf1;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
.createTitle {
|
.createTitle {
|
||||||
|
display: flex;
|
||||||
|
margin-left: 10px;
|
||||||
|
min-height: 47px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
color:#344767;
|
color:#344767;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@@ -48,7 +51,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.title {
|
.title {
|
||||||
margin-bottom: 20px;
|
margin: 10px 0;
|
||||||
|
min-height: 47px;
|
||||||
.name {
|
.name {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
|
|||||||
@@ -0,0 +1,343 @@
|
|||||||
|
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
|
||||||
|
import type { Ref } from 'react';
|
||||||
|
import { Button, Form, Input, Select, Row, Col, Space, Tooltip, Switch } from 'antd';
|
||||||
|
import { SENSITIVE_LEVEL_OPTIONS, TAG_DEFINE_TYPE } from '../constant';
|
||||||
|
import { formLayout } from '@/components/FormHelper/utils';
|
||||||
|
import SqlEditor from '@/components/SqlEditor';
|
||||||
|
import { ISemantic } from '../data';
|
||||||
|
import {
|
||||||
|
DIM_OPTIONS,
|
||||||
|
EnumDataSourceType,
|
||||||
|
PARTITION_TIME_FORMATTER,
|
||||||
|
DATE_FORMATTER,
|
||||||
|
} from '@/pages/SemanticModel/Datasource/constants';
|
||||||
|
import { InfoCircleOutlined } from '@ant-design/icons';
|
||||||
|
import {
|
||||||
|
createDimension,
|
||||||
|
updateDimension,
|
||||||
|
mockDimensionAlias,
|
||||||
|
batchCreateTag,
|
||||||
|
batchDeleteTag,
|
||||||
|
} from '../service';
|
||||||
|
import FormItemTitle from '@/components/FormHelper/FormItemTitle';
|
||||||
|
import { message } from 'antd';
|
||||||
|
import { toModelList } from '@/pages/SemanticModel/utils';
|
||||||
|
|
||||||
|
export type CreateFormProps = {
|
||||||
|
modelId: number;
|
||||||
|
domainId: number;
|
||||||
|
dimensionItem?: ISemantic.IDimensionItem;
|
||||||
|
onCancel: () => void;
|
||||||
|
onSubmit?: (values?: any) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const FormItem = Form.Item;
|
||||||
|
const { Option } = Select;
|
||||||
|
|
||||||
|
const { TextArea } = Input;
|
||||||
|
|
||||||
|
const DimensionInfoForm: React.FC<CreateFormProps> = forwardRef(
|
||||||
|
(
|
||||||
|
{ modelId, domainId, dimensionItem, onSubmit: handleUpdate }: CreateFormProps,
|
||||||
|
ref: Ref<any>,
|
||||||
|
) => {
|
||||||
|
const isEdit = !!dimensionItem?.id;
|
||||||
|
const [dimensionValueSettingList, setDimensionValueSettingList] = useState<
|
||||||
|
ISemantic.IDimensionValueSettingItem[]
|
||||||
|
>([]);
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
const { setFieldsValue, resetFields } = form;
|
||||||
|
const [llmLoading, setLlmLoading] = useState<boolean>(false);
|
||||||
|
const [formData, setFormData] = useState<ISemantic.IDimensionItem>();
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
onSave: () => {
|
||||||
|
return handleSubmit();
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const handleSubmit = async (dimValueMaps?: ISemantic.IDimensionValueSettingItem[]) => {
|
||||||
|
const fieldsValue = await form.validateFields();
|
||||||
|
await saveDimension({
|
||||||
|
...fieldsValue,
|
||||||
|
dimValueMaps: dimValueMaps || dimensionValueSettingList,
|
||||||
|
alias: Array.isArray(fieldsValue.alias) ? fieldsValue.alias.join(',') : '',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveDimension = async (fieldsValue: any) => {
|
||||||
|
const queryParams = {
|
||||||
|
modelId: isEdit ? dimensionItem.modelId : modelId,
|
||||||
|
type: 'categorical',
|
||||||
|
...fieldsValue,
|
||||||
|
};
|
||||||
|
let saveDimensionQuery = createDimension;
|
||||||
|
if (queryParams.id) {
|
||||||
|
saveDimensionQuery = updateDimension;
|
||||||
|
}
|
||||||
|
const { code, msg, data } = await saveDimensionQuery(queryParams);
|
||||||
|
if (code === 200) {
|
||||||
|
if (queryParams.isTag) {
|
||||||
|
queryBatchExportTag(data.id || dimensionItem?.id);
|
||||||
|
}
|
||||||
|
if (dimensionItem?.id && !queryParams.isTag) {
|
||||||
|
queryBatchDeleteTag(dimensionItem);
|
||||||
|
}
|
||||||
|
if (!isEdit) {
|
||||||
|
toModelList(domainId, modelId, 'dimension');
|
||||||
|
}
|
||||||
|
message.success('保存维度成功');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
message.error(msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
const queryBatchDeleteTag = async (dimensionItem: ISemantic.IDimensionItem) => {
|
||||||
|
const { code, msg } = await batchDeleteTag([
|
||||||
|
{
|
||||||
|
itemIds: [dimensionItem.id],
|
||||||
|
tagDefineType: TAG_DEFINE_TYPE.DIMENSION,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
if (code === 200) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
message.error(msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
const queryBatchExportTag = async (id: number) => {
|
||||||
|
const { code, msg } = await batchCreateTag([
|
||||||
|
{ itemId: id, tagDefineType: TAG_DEFINE_TYPE.DIMENSION },
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (code === 200) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
message.error(msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
const setFormVal = () => {
|
||||||
|
if (dimensionItem) {
|
||||||
|
const { alias } = dimensionItem;
|
||||||
|
const dimensionData = {
|
||||||
|
...dimensionItem,
|
||||||
|
alias: alias && alias.trim() ? alias.split(',') : [],
|
||||||
|
};
|
||||||
|
setFieldsValue(dimensionData);
|
||||||
|
setFormData(dimensionData);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (dimensionItem) {
|
||||||
|
setFormVal();
|
||||||
|
if (Array.isArray(dimensionItem.dimValueMaps)) {
|
||||||
|
setDimensionValueSettingList(dimensionItem.dimValueMaps);
|
||||||
|
} else {
|
||||||
|
setDimensionValueSettingList([]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resetFields();
|
||||||
|
}
|
||||||
|
}, [dimensionItem]);
|
||||||
|
|
||||||
|
const generatorDimensionAlias = async () => {
|
||||||
|
const fieldsValue = await form.validateFields();
|
||||||
|
setLlmLoading(true);
|
||||||
|
const { code, data } = await mockDimensionAlias({
|
||||||
|
...dimensionItem,
|
||||||
|
...fieldsValue,
|
||||||
|
alias: fieldsValue.alias?.join(','),
|
||||||
|
});
|
||||||
|
setLlmLoading(false);
|
||||||
|
const formAlias = form.getFieldValue('alias');
|
||||||
|
setLlmLoading(false);
|
||||||
|
if (code === 200) {
|
||||||
|
form.setFieldValue('alias', Array.from(new Set([...formAlias, ...data])));
|
||||||
|
} else {
|
||||||
|
message.error('大语言模型解析异常');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderContent = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<FormItem hidden={true} name="id" label="ID">
|
||||||
|
<Input placeholder="id" />
|
||||||
|
</FormItem>
|
||||||
|
<FormItem
|
||||||
|
name="name"
|
||||||
|
label="维度名称"
|
||||||
|
rules={[{ required: true, message: '请输入维度名称' }]}
|
||||||
|
>
|
||||||
|
<Input placeholder="名称不可重复" />
|
||||||
|
</FormItem>
|
||||||
|
<FormItem
|
||||||
|
hidden={isEdit}
|
||||||
|
name="bizName"
|
||||||
|
label="英文名称"
|
||||||
|
rules={[{ required: true, message: '请输入英文名称' }]}
|
||||||
|
>
|
||||||
|
<Input placeholder="名称不可重复" disabled={isEdit} />
|
||||||
|
</FormItem>
|
||||||
|
<FormItem label="别名">
|
||||||
|
<Row>
|
||||||
|
<Col flex="1 1 200px">
|
||||||
|
<FormItem name="alias" noStyle>
|
||||||
|
<Select
|
||||||
|
mode="tags"
|
||||||
|
placeholder="输入别名后回车确认,多别名输入、复制粘贴支持英文逗号自动分隔"
|
||||||
|
tokenSeparators={[',']}
|
||||||
|
maxTagCount={9}
|
||||||
|
/>
|
||||||
|
</FormItem>
|
||||||
|
</Col>
|
||||||
|
{isEdit && (
|
||||||
|
<Col flex="0 1 75px">
|
||||||
|
<Button
|
||||||
|
type="link"
|
||||||
|
size="small"
|
||||||
|
loading={llmLoading}
|
||||||
|
style={{ top: '2px' }}
|
||||||
|
onClick={() => {
|
||||||
|
generatorDimensionAlias();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Space>
|
||||||
|
智能填充
|
||||||
|
<Tooltip title="智能填充将根据维度相关信息,使用大语言模型获取维度别名">
|
||||||
|
<InfoCircleOutlined />
|
||||||
|
</Tooltip>
|
||||||
|
</Space>
|
||||||
|
</Button>
|
||||||
|
</Col>
|
||||||
|
)}
|
||||||
|
</Row>
|
||||||
|
</FormItem>
|
||||||
|
<FormItem
|
||||||
|
name="type"
|
||||||
|
label="类型"
|
||||||
|
rules={[{ required: true, message: '请选择维度类型' }]}
|
||||||
|
>
|
||||||
|
<Select placeholder="请选择维度类型">
|
||||||
|
{DIM_OPTIONS.map((item) => (
|
||||||
|
<Option key={item.value} value={item.value}>
|
||||||
|
{item.label}
|
||||||
|
</Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormItem>
|
||||||
|
{formData?.type &&
|
||||||
|
[EnumDataSourceType.PARTITION_TIME, EnumDataSourceType.TIME].includes(
|
||||||
|
formData.type as EnumDataSourceType,
|
||||||
|
) && (
|
||||||
|
<FormItem
|
||||||
|
name={['ext', 'time_format']}
|
||||||
|
label="时间格式"
|
||||||
|
rules={[{ required: true, message: '请选择时间格式' }]}
|
||||||
|
tooltip="请选择数据库中时间字段对应格式"
|
||||||
|
>
|
||||||
|
<Select placeholder="请选择维度类型">
|
||||||
|
{(formData?.type === EnumDataSourceType.TIME
|
||||||
|
? DATE_FORMATTER
|
||||||
|
: PARTITION_TIME_FORMATTER
|
||||||
|
).map((item) => (
|
||||||
|
<Option key={item} value={item}>
|
||||||
|
{item}
|
||||||
|
</Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<FormItem
|
||||||
|
name="semanticType"
|
||||||
|
label="类型"
|
||||||
|
hidden={true}
|
||||||
|
// rules={[{ required: true, message: '请选择维度类型' }]}
|
||||||
|
>
|
||||||
|
<Select placeholder="请选择维度类型">
|
||||||
|
{['CATEGORY', 'ID', 'DATE'].map((item) => (
|
||||||
|
<Option key={item} value={item}>
|
||||||
|
{item}
|
||||||
|
</Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormItem>
|
||||||
|
<FormItem
|
||||||
|
name="sensitiveLevel"
|
||||||
|
label="敏感度"
|
||||||
|
rules={[{ required: true, message: '请选择敏感度' }]}
|
||||||
|
>
|
||||||
|
<Select placeholder="请选择敏感度">
|
||||||
|
{SENSITIVE_LEVEL_OPTIONS.map((item) => (
|
||||||
|
<Option key={item.value} value={item.value}>
|
||||||
|
{item.label}
|
||||||
|
</Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormItem>
|
||||||
|
{/* <FormItem name="commonDimensionId" label="公共维度">
|
||||||
|
<Select placeholder="请绑定公共维度" allowClear options={commonDimensionOptions} />
|
||||||
|
</FormItem> */}
|
||||||
|
{/* <FormItem name="defaultValues" label="默认值">
|
||||||
|
<InfoTagList />
|
||||||
|
</FormItem> */}
|
||||||
|
<Form.Item
|
||||||
|
hidden={!!!process.env.SHOW_TAG}
|
||||||
|
label={
|
||||||
|
<FormItemTitle
|
||||||
|
title={`设为标签`}
|
||||||
|
subTitle={`如果勾选,代表维度的取值都是一种'标签',可用作对实体的圈选`}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
name="isTag"
|
||||||
|
valuePropName="checked"
|
||||||
|
getValueFromEvent={(value) => {
|
||||||
|
return value === true ? 1 : 0;
|
||||||
|
}}
|
||||||
|
getValueProps={(value) => {
|
||||||
|
return {
|
||||||
|
checked: value === 1,
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
|
<FormItem
|
||||||
|
name="description"
|
||||||
|
label="维度描述"
|
||||||
|
rules={[{ required: true, message: '请输入维度描述' }]}
|
||||||
|
>
|
||||||
|
<TextArea placeholder="请输入维度描述" />
|
||||||
|
</FormItem>
|
||||||
|
<FormItem
|
||||||
|
name="expr"
|
||||||
|
label="表达式"
|
||||||
|
tooltip="表达式中的字段必须在创建模型的时候被标记为日期或者维度"
|
||||||
|
rules={[{ required: true, message: '请输入表达式' }]}
|
||||||
|
>
|
||||||
|
<SqlEditor height={'150px'} />
|
||||||
|
</FormItem>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Form
|
||||||
|
{...formLayout}
|
||||||
|
form={form}
|
||||||
|
onValuesChange={(value, values) => {
|
||||||
|
setFormData(values);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{renderContent()}
|
||||||
|
</Form>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export default DimensionInfoForm;
|
||||||
@@ -13,7 +13,7 @@ import IndicatorStar, { StarType } from '../components/IndicatorStar';
|
|||||||
interface IndicatorInfo {
|
interface IndicatorInfo {
|
||||||
url?: string;
|
url?: string;
|
||||||
starType?: StarType;
|
starType?: StarType;
|
||||||
onNameClick?: (record: ISemantic.IMetricItem) => void | boolean;
|
onNameClick?: (record: ISemantic.IMetricItem | ISemantic.IDimensionItem) => void | boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ColumnsConfigParams {
|
interface ColumnsConfigParams {
|
||||||
@@ -116,18 +116,43 @@ export const ColumnsConfig = (params?: ColumnsConfigParams) => {
|
|||||||
},
|
},
|
||||||
dimensionInfo: {
|
dimensionInfo: {
|
||||||
render: (_, record: ISemantic.IDimensionItem) => {
|
render: (_, record: ISemantic.IDimensionItem) => {
|
||||||
const { name, alias, bizName } = record;
|
const { name, alias, bizName, id, domainId, modelId } = record;
|
||||||
|
let url = `/demension/detail/${id}`;
|
||||||
|
if (params?.indicatorInfo) {
|
||||||
|
url = replaceRouteParams(params.indicatorInfo.url || '', {
|
||||||
|
domainId: `${domainId}`,
|
||||||
|
modelId: `${modelId}`,
|
||||||
|
indicatorId: `${id}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div>
|
<div>
|
||||||
<Space>
|
<Space>
|
||||||
<span style={{ fontWeight: 500 }}>{name}</span>
|
<a
|
||||||
|
className={styles.textLink}
|
||||||
|
style={{ fontWeight: 500 }}
|
||||||
|
onClick={(event: any) => {
|
||||||
|
if (params?.indicatorInfo?.onNameClick) {
|
||||||
|
const state = params.indicatorInfo.onNameClick(record);
|
||||||
|
if (state === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
history.push(url);
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{name}
|
||||||
|
</a>
|
||||||
|
{/* <span style={{ fontWeight: 500 }}>{name}</span> */}
|
||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ color: '#5f748d', fontSize: 14, marginTop: 5, marginLeft: 0 }}>
|
<div style={{ color: '#5f748d', fontSize: 14, marginTop: 5, marginLeft: 0 }}>
|
||||||
{bizName}
|
{bizName}
|
||||||
</div>
|
</div>
|
||||||
{renderAliasAndClassifications(alias, undefined)}
|
{alias && renderAliasAndClassifications(alias, undefined)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -174,7 +199,7 @@ export const ColumnsConfig = (params?: ColumnsConfigParams) => {
|
|||||||
<div style={{ color: '#5f748d', fontSize: 14, marginTop: 5, marginLeft: 0 }}>
|
<div style={{ color: '#5f748d', fontSize: 14, marginTop: 5, marginLeft: 0 }}>
|
||||||
{bizName}
|
{bizName}
|
||||||
</div>
|
</div>
|
||||||
{renderAliasAndClassifications(alias, classifications)}
|
{alias && renderAliasAndClassifications(alias, classifications)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -24,6 +24,13 @@ const SemanticModel: React.FC<Props> = ({}) => {
|
|||||||
|
|
||||||
const { selectMetric, setSelectMetric } = metricModel;
|
const { selectMetric, setSelectMetric } = metricModel;
|
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
|
||||||
|
// return () => {
|
||||||
|
// setSelectMetric(undefined);
|
||||||
|
// }
|
||||||
|
// }, [])
|
||||||
|
|
||||||
const initSelectedDomain = (domainList: ISemantic.IDomainItem[]) => {
|
const initSelectedDomain = (domainList: ISemantic.IDomainItem[]) => {
|
||||||
const targetNode = domainList.filter((item: any) => {
|
const targetNode = domainList.filter((item: any) => {
|
||||||
return `${item.id}` === domainId;
|
return `${item.id}` === domainId;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { getDimensionList } from '../service';
|
|||||||
|
|
||||||
export default function Dimension() {
|
export default function Dimension() {
|
||||||
const [dimensionList, setDimensionList] = useState<ISemantic.IDimensionItem[]>([]);
|
const [dimensionList, setDimensionList] = useState<ISemantic.IDimensionItem[]>([]);
|
||||||
|
const [selectDimension, setSelectDimension] = useState<ISemantic.IDimensionItem>();
|
||||||
|
|
||||||
const queryDimensionList = async (params: any) => {
|
const queryDimensionList = async (params: any) => {
|
||||||
const { code, data, msg } = await getDimensionList({
|
const { code, data, msg } = await getDimensionList({
|
||||||
@@ -23,5 +24,10 @@ export default function Dimension() {
|
|||||||
return await queryDimensionList(params);
|
return await queryDimensionList(params);
|
||||||
};
|
};
|
||||||
|
|
||||||
return { MdimensionList: dimensionList, MrefreshDimensionList: refreshDimensionList };
|
return {
|
||||||
|
MdimensionList: dimensionList,
|
||||||
|
MrefreshDimensionList: refreshDimensionList,
|
||||||
|
selectDimension,
|
||||||
|
setSelectDimension,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,37 @@
|
|||||||
import { ISemantic } from '../data';
|
import { ISemantic } from '../data';
|
||||||
import { useState } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
|
import { useModel } from '@umijs/max';
|
||||||
|
|
||||||
export default function Domain() {
|
export default function Domain() {
|
||||||
const [selectDomain, setSelectDomain] = useState<ISemantic.IDomainItem>(
|
const [selectDomain, setSelectDomain] = useState<ISemantic.IDomainItem>(
|
||||||
{} as ISemantic.IDomainItem,
|
{} as ISemantic.IDomainItem,
|
||||||
);
|
);
|
||||||
|
const [selectDataSet, setSelectDataSet] = useState<ISemantic.IDatasetItem>();
|
||||||
const [domainList, setDomainList] = useState<ISemantic.IDomainItem[]>([]);
|
const [domainList, setDomainList] = useState<ISemantic.IDomainItem[]>([]);
|
||||||
|
|
||||||
|
const modelModel = useModel('SemanticModel.modelData');
|
||||||
|
const metricModel = useModel('SemanticModel.metricData');
|
||||||
|
const dimensionModel = useModel('SemanticModel.dimensionData');
|
||||||
|
|
||||||
|
const { setSelectModel } = modelModel;
|
||||||
|
const { setSelectDimension } = dimensionModel;
|
||||||
|
const { setSelectMetric } = metricModel;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setSelectModel(undefined);
|
||||||
|
setSelectDimension(undefined);
|
||||||
|
setSelectMetric(undefined);
|
||||||
|
setSelectDataSet(undefined);
|
||||||
|
}, [selectDomain]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
selectDomain,
|
selectDomain,
|
||||||
|
selectDataSet,
|
||||||
selectDomainId: selectDomain?.id,
|
selectDomainId: selectDomain?.id,
|
||||||
selectDomainName: selectDomain?.name,
|
selectDomainName: selectDomain?.name,
|
||||||
domainList,
|
domainList,
|
||||||
setSelectDomain,
|
setSelectDomain,
|
||||||
|
setSelectDataSet,
|
||||||
setDomainList,
|
setDomainList,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { ISemantic } from '../data';
|
import { ISemantic } from '../data';
|
||||||
import { message } from 'antd';
|
import { message } from 'antd';
|
||||||
import { useState } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
|
import { useModel } from '@umijs/max';
|
||||||
import { getModelList } from '../service';
|
import { getModelList } from '../service';
|
||||||
|
|
||||||
export default function Model() {
|
export default function Model() {
|
||||||
@@ -8,6 +9,17 @@ export default function Model() {
|
|||||||
const [modelList, setModelList] = useState<ISemantic.IModelItem[]>([]);
|
const [modelList, setModelList] = useState<ISemantic.IModelItem[]>([]);
|
||||||
const [modelTableHistoryParams, setModelTableHistoryParams] = useState<Record<string, any>>({});
|
const [modelTableHistoryParams, setModelTableHistoryParams] = useState<Record<string, any>>({});
|
||||||
|
|
||||||
|
const metricModel = useModel('SemanticModel.metricData');
|
||||||
|
const dimensionModel = useModel('SemanticModel.dimensionData');
|
||||||
|
|
||||||
|
const { setSelectDimension } = dimensionModel;
|
||||||
|
const { setSelectMetric } = metricModel;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setSelectDimension(undefined);
|
||||||
|
setSelectMetric(undefined);
|
||||||
|
}, [selectModel]);
|
||||||
|
|
||||||
const mergeParams = (params: Record<string, any>) => {
|
const mergeParams = (params: Record<string, any>) => {
|
||||||
setModelTableHistoryParams({
|
setModelTableHistoryParams({
|
||||||
...modelTableHistoryParams,
|
...modelTableHistoryParams,
|
||||||
|
|||||||
@@ -50,9 +50,6 @@ export function getDimensionList(data: any): Promise<any> {
|
|||||||
...(modelId ? { modelIds: [modelId] } : {}),
|
...(modelId ? { modelIds: [modelId] } : {}),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
if (getRunningEnv() === 'chat') {
|
|
||||||
return request.post(`${process.env.CHAT_API_BASE_URL}conf/dimension/page`, queryParams);
|
|
||||||
}
|
|
||||||
return request.post(`${process.env.API_BASE_URL}dimension/queryDimension`, queryParams);
|
return request.post(`${process.env.API_BASE_URL}dimension/queryDimension`, queryParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -253,10 +253,26 @@ export const toModelList = (domainId: number, modelId: number, menuKey?: string)
|
|||||||
history.push(`/model/domain/manager/${domainId}/${modelId}${menuKey ? `/${menuKey}` : ''}`);
|
history.push(`/model/domain/manager/${domainId}/${modelId}${menuKey ? `/${menuKey}` : ''}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const toMetricEditPage = (domainId: number, modelId: number, metircId: number) => {
|
export const toMetricEditPage = (
|
||||||
history.push(`/model/metric/${domainId}/${modelId}/${metircId}`);
|
domainId: number,
|
||||||
|
modelId: number,
|
||||||
|
metircId: number,
|
||||||
|
menuKey?: string,
|
||||||
|
) => {
|
||||||
|
history.push(`/model/metric/${domainId}/${modelId}/${metircId}${menuKey ? `/${menuKey}` : ''}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const toDatasetEditPage = (domainId: number, datasetId: number) => {
|
export const toDatasetEditPage = (domainId: number, datasetId: number, menuKey?: string) => {
|
||||||
history.push(`/model/dataset/${domainId}/${datasetId}`);
|
history.push(`/model/dataset/${domainId}/${datasetId}${menuKey ? `/${menuKey}` : ''}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const toDimensionEditPage = (
|
||||||
|
domainId: number,
|
||||||
|
modelId: number,
|
||||||
|
dimensionId: number,
|
||||||
|
menuKey?: string,
|
||||||
|
) => {
|
||||||
|
history.push(
|
||||||
|
`/model/dimension/${domainId}/${modelId}/${dimensionId}${menuKey ? `/${menuKey}` : ''}`,
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user