mirror of
https://github.com/tencentmusic/supersonic.git
synced 2025-12-10 02:46:56 +00:00
[improvement][semantic-fe] metric market experience optimization (#109)
* [improvement][semantic-fe] Add model alias setting & Add view permission restrictions to the model permission management tab. [improvement][semantic-fe] Add permission control to the action buttons for the main domain; apply high sensitivity filtering to the authorization of metrics/dimensions. [improvement][semantic-fe] Optimize the editing mode in the dimension/metric/datasource components to use the modelId stored in the database for data, instead of relying on the data from the state manager. * [improvement][semantic-fe] Add time granularity setting in the data source configuration. * [improvement][semantic-fe] Dictionary import for dimension values supported in Q&A visibility * [improvement][semantic-fe] Modification of data source creation prompt wording" * [improvement][semantic-fe] metric market experience optimization
This commit is contained in:
@@ -81,7 +81,7 @@ const MetricFilter: React.FC<Props> = ({ filterValues = {}, onFiltersChange }) =
|
||||
<FormItem name="key" noStyle>
|
||||
<div className={styles.searchInput}>
|
||||
<Input.Search
|
||||
placeholder="请输入需要查询指标的ID、指标名称、字段名称"
|
||||
placeholder="请输入需要查询指标的ID、指标名称、字段名称、标签"
|
||||
enterButton={<SearchOutlined style={{ marginTop: 5 }} />}
|
||||
onSearch={(value) => {
|
||||
onSearch(value);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { ActionType, ProColumns } from '@ant-design/pro-table';
|
||||
import ProTable from '@ant-design/pro-table';
|
||||
import { message, Space, Popconfirm } from 'antd';
|
||||
import { message, Space, Popconfirm, Tag } from 'antd';
|
||||
import React, { useRef, useState, useEffect } from 'react';
|
||||
import type { Dispatch } from 'umi';
|
||||
import { connect } from 'umi';
|
||||
import { connect, history } from 'umi';
|
||||
import type { StateType } from '../model';
|
||||
import { SENSITIVE_LEVEL_ENUM } from '../constant';
|
||||
import { queryMetric, deleteMetric } from '../service';
|
||||
@@ -89,6 +89,20 @@ const ClassMetricTable: React.FC<Props> = ({ domainManger, dispatch }) => {
|
||||
{
|
||||
dataIndex: 'name',
|
||||
title: '指标名称',
|
||||
render: (_, record: any) => {
|
||||
if (record.hasAdminRes) {
|
||||
return (
|
||||
<a
|
||||
onClick={() => {
|
||||
history.replace(`/model/${record.domainId}/${record.modelId}/metric`);
|
||||
}}
|
||||
>
|
||||
{record.name}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
return <> {record.name}</>;
|
||||
},
|
||||
},
|
||||
// {
|
||||
// dataIndex: 'alias',
|
||||
@@ -113,6 +127,25 @@ const ClassMetricTable: React.FC<Props> = ({ domainManger, dispatch }) => {
|
||||
title: '创建人',
|
||||
search: false,
|
||||
},
|
||||
{
|
||||
dataIndex: 'tags',
|
||||
title: '标签',
|
||||
search: false,
|
||||
render: (tags) => {
|
||||
if (Array.isArray(tags)) {
|
||||
return (
|
||||
<Space size={2}>
|
||||
{tags.map((tag) => (
|
||||
<Tag color="blue" key={tag}>
|
||||
{tag}
|
||||
</Tag>
|
||||
))}
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
return <>--</>;
|
||||
},
|
||||
},
|
||||
{
|
||||
dataIndex: 'description',
|
||||
title: '描述',
|
||||
@@ -140,43 +173,47 @@ const ClassMetricTable: React.FC<Props> = ({ domainManger, dispatch }) => {
|
||||
dataIndex: 'x',
|
||||
valueType: 'option',
|
||||
render: (_, record) => {
|
||||
return (
|
||||
<Space>
|
||||
<a
|
||||
key="metricEditBtn"
|
||||
onClick={() => {
|
||||
setMetricItem(record);
|
||||
setCreateModalVisible(true);
|
||||
}}
|
||||
>
|
||||
编辑
|
||||
</a>
|
||||
|
||||
<Popconfirm
|
||||
title="确认删除?"
|
||||
okText="是"
|
||||
cancelText="否"
|
||||
onConfirm={async () => {
|
||||
const { code, msg } = await deleteMetric(record.id);
|
||||
if (code === 200) {
|
||||
setMetricItem(undefined);
|
||||
actionRef.current?.reload();
|
||||
} else {
|
||||
message.error(msg);
|
||||
}
|
||||
}}
|
||||
>
|
||||
if (record.hasAdminRes) {
|
||||
return (
|
||||
<Space>
|
||||
<a
|
||||
key="metricDeleteBtn"
|
||||
key="metricEditBtn"
|
||||
onClick={() => {
|
||||
setMetricItem(record);
|
||||
setCreateModalVisible(true);
|
||||
}}
|
||||
>
|
||||
删除
|
||||
编辑
|
||||
</a>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
);
|
||||
|
||||
<Popconfirm
|
||||
title="确认删除?"
|
||||
okText="是"
|
||||
cancelText="否"
|
||||
onConfirm={async () => {
|
||||
const { code, msg } = await deleteMetric(record.id);
|
||||
if (code === 200) {
|
||||
setMetricItem(undefined);
|
||||
queryMetricList();
|
||||
} else {
|
||||
message.error(msg);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<a
|
||||
key="metricDeleteBtn"
|
||||
onClick={() => {
|
||||
setMetricItem(record);
|
||||
}}
|
||||
>
|
||||
删除
|
||||
</a>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
);
|
||||
} else {
|
||||
return <></>;
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -239,7 +276,7 @@ const ClassMetricTable: React.FC<Props> = ({ domainManger, dispatch }) => {
|
||||
metricItem={metricItem}
|
||||
onSubmit={() => {
|
||||
setCreateModalVisible(false);
|
||||
actionRef?.current?.reload();
|
||||
queryMetricList();
|
||||
dispatch({
|
||||
type: 'domainManger/queryMetricList',
|
||||
payload: {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
// margin-bottom: 12px;
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
width: 500px;
|
||||
width: 540px;
|
||||
margin: 0 auto;
|
||||
.searchInput {
|
||||
width: 100%;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { ActionType, ProColumns } from '@ant-design/pro-table';
|
||||
import ProTable from '@ant-design/pro-table';
|
||||
import { message, Button, Space, Popconfirm, Input } from 'antd';
|
||||
import { message, Button, Space, Popconfirm, Input, Tag } from 'antd';
|
||||
import React, { useRef, useState } from 'react';
|
||||
import type { Dispatch } from 'umi';
|
||||
import { connect } from 'umi';
|
||||
@@ -76,7 +76,7 @@ const ClassMetricTable: React.FC<Props> = ({ domainManger, dispatch }) => {
|
||||
dataIndex: 'key',
|
||||
title: '指标搜索',
|
||||
hideInTable: true,
|
||||
renderFormItem: () => <Input placeholder="请输入ID/指标名称/字段名称" />,
|
||||
renderFormItem: () => <Input placeholder="请输入ID/指标名称/字段名称/标签" />,
|
||||
},
|
||||
{
|
||||
dataIndex: 'alias',
|
||||
@@ -101,6 +101,25 @@ const ClassMetricTable: React.FC<Props> = ({ domainManger, dispatch }) => {
|
||||
title: '创建人',
|
||||
search: false,
|
||||
},
|
||||
{
|
||||
dataIndex: 'tags',
|
||||
title: '标签',
|
||||
search: false,
|
||||
render: (tags) => {
|
||||
if (Array.isArray(tags)) {
|
||||
return (
|
||||
<Space size={2} wrap>
|
||||
{tags.map((tag) => (
|
||||
<Tag color="blue" key={tag}>
|
||||
{tag}
|
||||
</Tag>
|
||||
))}
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
return <>--</>;
|
||||
},
|
||||
},
|
||||
{
|
||||
dataIndex: 'description',
|
||||
title: '描述',
|
||||
|
||||
@@ -24,7 +24,7 @@ import FormItemTitle from '@/components/FormHelper/FormItemTitle';
|
||||
import styles from './style.less';
|
||||
import { getMeasureListByModelId } from '../service';
|
||||
import TableTitleTooltips from '../components/TableTitleTooltips';
|
||||
import { creatExprMetric, updateExprMetric, mockMetricAlias } from '../service';
|
||||
import { creatExprMetric, updateExprMetric, mockMetricAlias, getMetricTags } from '../service';
|
||||
import { ISemantic } from '../data';
|
||||
import { history } from 'umi';
|
||||
|
||||
@@ -75,6 +75,8 @@ const MetricInfoCreateForm: React.FC<CreateFormProps> = ({
|
||||
const [hasMeasuresState, setHasMeasuresState] = useState<boolean>(true);
|
||||
const [llmLoading, setLlmLoading] = useState<boolean>(false);
|
||||
|
||||
const [tagOptions, setTagOptions] = useState<{ label: string; value: string }[]>([]);
|
||||
|
||||
const forward = () => setCurrentStep(currentStep + 1);
|
||||
const backward = () => setCurrentStep(currentStep - 1);
|
||||
|
||||
@@ -95,6 +97,7 @@ const MetricInfoCreateForm: React.FC<CreateFormProps> = ({
|
||||
|
||||
useEffect(() => {
|
||||
queryClassMeasureList();
|
||||
queryMetricTags();
|
||||
}, []);
|
||||
|
||||
const handleNext = async () => {
|
||||
@@ -126,6 +129,7 @@ const MetricInfoCreateForm: React.FC<CreateFormProps> = ({
|
||||
dataFormat,
|
||||
dataFormatType,
|
||||
alias,
|
||||
tags,
|
||||
} = metricItem as any;
|
||||
const isPercent = dataFormatType === 'percent';
|
||||
const isDecimal = dataFormatType === 'decimal';
|
||||
@@ -135,6 +139,7 @@ const MetricInfoCreateForm: React.FC<CreateFormProps> = ({
|
||||
bizName,
|
||||
sensitiveLevel,
|
||||
description,
|
||||
tags,
|
||||
// isPercent,
|
||||
dataFormatType: dataFormatType || '',
|
||||
alias: alias && alias.trim() ? alias.split(',') : [],
|
||||
@@ -204,6 +209,22 @@ const MetricInfoCreateForm: React.FC<CreateFormProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
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 (
|
||||
@@ -277,6 +298,15 @@ const MetricInfoCreateForm: React.FC<CreateFormProps> = ({
|
||||
)}
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem name="tags" label="标签">
|
||||
<Select
|
||||
mode="tags"
|
||||
placeholder="输入别名后回车确认,多别名输入、复制粘贴支持英文逗号自动分隔"
|
||||
tokenSeparators={[',']}
|
||||
maxTagCount={9}
|
||||
options={tagOptions}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
name="sensitiveLevel"
|
||||
label="敏感度"
|
||||
|
||||
@@ -41,6 +41,7 @@ const PermissionAdminForm: React.FC<Props> = ({
|
||||
...data,
|
||||
};
|
||||
fieldsValue.admins = fieldsValue.admins || [];
|
||||
fieldsValue.adminOrgs = fieldsValue.adminOrgs || [];
|
||||
fieldsValue.viewers = fieldsValue.viewers || [];
|
||||
fieldsValue.viewOrgs = fieldsValue.viewOrgs || [];
|
||||
fieldsValue.isOpen = !!fieldsValue.isOpen;
|
||||
@@ -57,10 +58,11 @@ const PermissionAdminForm: React.FC<Props> = ({
|
||||
|
||||
const saveAuth = async () => {
|
||||
const values = await form.validateFields();
|
||||
const { admins, isOpen, viewOrgs = [], viewers = [] } = values;
|
||||
const { admins, adminOrgs, isOpen, viewOrgs = [], viewers = [] } = values;
|
||||
const queryClassData = {
|
||||
...classDetail,
|
||||
admins,
|
||||
adminOrgs,
|
||||
viewOrgs,
|
||||
viewers,
|
||||
isOpen: isOpen ? 1 : 0,
|
||||
@@ -100,7 +102,16 @@ const PermissionAdminForm: React.FC<Props> = ({
|
||||
>
|
||||
<SelectTMEPerson placeholder="请邀请团队成员" />
|
||||
</FormItem>
|
||||
|
||||
{APP_TARGET === 'inner' && (
|
||||
<FormItem name="adminOrgs" label="按组织">
|
||||
<SelectPartner
|
||||
type="selectedDepartment"
|
||||
treeSelectProps={{
|
||||
placeholder: '请选择需要授权的部门',
|
||||
}}
|
||||
/>
|
||||
</FormItem>
|
||||
)}
|
||||
<Form.Item
|
||||
label={
|
||||
<FormItemTitle
|
||||
|
||||
@@ -119,6 +119,10 @@ export function mockMetricAlias(data: any): Promise<any> {
|
||||
});
|
||||
}
|
||||
|
||||
export function getMetricTags(): Promise<any> {
|
||||
return request.get(`${process.env.API_BASE_URL}metric/getMetricTags`);
|
||||
}
|
||||
|
||||
export function getMeasureListByModelId(modelId: number): Promise<any> {
|
||||
return request.get(`${process.env.API_BASE_URL}datasource/getMeasureListOfModel/${modelId}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user