[improvement][semantic-fe] Restructured the code to extract the question-answer settings and model management model controls into the OverviewContainer component.

This commit is contained in:
tristanliu
2023-08-15 10:40:58 +08:00
parent b1952d64ab
commit c3d3b1146b
48 changed files with 1104 additions and 863 deletions

View File

@@ -113,6 +113,7 @@ const BindMeasuresTable: React.FC<CreateFormProps> = ({
size="small"
search={false}
options={false}
scroll={{ y: 800 }}
/>
</Modal>
);

View File

@@ -15,7 +15,7 @@ type Props = {
};
const ClassDataSourceTable: React.FC<Props> = ({ dispatch, domainManger }) => {
const { selectDomainId } = domainManger;
const { selectModelId } = domainManger;
const [dataSourceItem, setDataSourceItem] = useState<any>();
const [createDataSourceModalOpen, setCreateDataSourceModalOpen] = useState(false);
@@ -59,7 +59,7 @@ const ClassDataSourceTable: React.FC<Props> = ({ dispatch, domainManger }) => {
return (
<Space>
<a
key="classEditBtn"
key="datasourceEditBtn"
onClick={() => {
setDataSourceItem(record);
setCreateDataSourceModalOpen(true);
@@ -82,7 +82,7 @@ const ClassDataSourceTable: React.FC<Props> = ({ dispatch, domainManger }) => {
}}
>
<a
key="classEditBtn"
key="datasourceDeleteBtn"
onClick={() => {
setDataSourceItem(record);
}}
@@ -127,7 +127,7 @@ const ClassDataSourceTable: React.FC<Props> = ({ dispatch, domainManger }) => {
actionRef={actionRef}
rowKey="id"
columns={columns}
params={{ domainId: selectDomainId }}
params={{ modelId: selectModelId }}
request={queryDataSourceList}
pagination={false}
search={false}

View File

@@ -28,7 +28,7 @@ const ClassDataSourceTypeModal: React.FC<Props> = ({
onCancel,
dispatch,
}) => {
const { selectDomainId, dataBaseConfig } = domainManger;
const { selectDomainId, dataBaseConfig, selectModelId } = domainManger;
const [createModalVisible, setCreateModalVisible] = useState<boolean>(false);
const [dataSourceModalVisible, setDataSourceModalVisible] = useState(false);
@@ -128,7 +128,7 @@ const ClassDataSourceTypeModal: React.FC<Props> = ({
type="primary"
key="console"
onClick={() => {
history.replace(`/semanticModel/${selectDomainId}/dataBase`);
history.replace(`/semanticModel/${selectDomainId}/0/dataBase`);
onCancel?.();
}}
>
@@ -173,7 +173,6 @@ const ClassDataSourceTypeModal: React.FC<Props> = ({
>
<DataSource
initialValues={dataSourceItem}
domainId={Number(selectDomainId)}
onSubmitSuccess={() => {
setCreateModalVisible(false);
onSubmit?.();

View File

@@ -1,101 +0,0 @@
import { Modal, Card, Row, Col, Result, Button } from 'antd';
import { ConsoleSqlOutlined, CoffeeOutlined } from '@ant-design/icons';
import React, { useState, useEffect } from 'react';
import { history, connect } from 'umi';
import type { StateType } from '../model';
const { Meta } = Card;
type Props = {
open: boolean;
domainManger: StateType;
onTypeChange: (type: 'fast' | 'normal') => void;
onCancel?: () => void;
};
const ClassDataSourceTypeModal: React.FC<Props> = ({
open,
onTypeChange,
domainManger,
onCancel,
}) => {
const { selectDomainId, dataBaseConfig } = domainManger;
const [createDataSourceModalOpen, setCreateDataSourceModalOpen] = useState(false);
useEffect(() => {
setCreateDataSourceModalOpen(open);
}, [open]);
return (
<>
<Modal
open={createDataSourceModalOpen}
onCancel={() => {
setCreateDataSourceModalOpen(false);
onCancel?.();
}}
footer={null}
centered
closable={false}
>
{dataBaseConfig && dataBaseConfig.id ? (
<Row gutter={16} style={{ marginTop: '0px' }}>
<Col span={12}>
<Card
hoverable
style={{ height: 220 }}
onClick={() => {
onTypeChange('fast');
setCreateDataSourceModalOpen(false);
}}
cover={
<CoffeeOutlined
width={240}
style={{ paddingTop: '45px', height: 120, fontSize: '48px', color: '#1890ff' }}
/>
}
>
<Meta title="快速创建" description="自动进行数据源可视化创建" />
</Card>
</Col>
<Col span={12}>
<Card
onClick={() => {
onTypeChange('normal');
setCreateDataSourceModalOpen(false);
}}
hoverable
style={{ height: 220 }}
cover={
<ConsoleSqlOutlined
style={{ paddingTop: '45px', height: 120, fontSize: '48px', color: '#1890ff' }}
/>
}
>
<Meta title="SQL脚本" description="自定义SQL脚本创建数据源" />
</Card>
</Col>
</Row>
) : (
<Result
status="warning"
subTitle="创建数据源需要先完成数据库设置"
extra={
<Button
type="primary"
key="console"
onClick={() => {
history.replace(`/semanticModel/${selectDomainId}/dataBase`);
onCancel?.();
}}
>
</Button>
}
/>
)}
</Modal>
</>
);
};
export default connect(({ domainManger }: { domainManger: StateType }) => ({
domainManger,
}))(ClassDataSourceTypeModal);

View File

@@ -19,7 +19,7 @@ type Props = {
};
const ClassDimensionTable: React.FC<Props> = ({ domainManger, dispatch }) => {
const { selectDomainId } = domainManger;
const { selectModelId: modelId } = domainManger;
const [createModalVisible, setCreateModalVisible] = useState<boolean>(false);
const [dimensionItem, setDimensionItem] = useState<ISemantic.IDimensionItem>();
const [dataSourceList, setDataSourceList] = useState<any[]>([]);
@@ -40,7 +40,7 @@ const ClassDimensionTable: React.FC<Props> = ({ domainManger, dispatch }) => {
const { code, data, msg } = await getDimensionList({
...params,
...pagination,
domainId: selectDomainId,
modelId,
});
const { list, pageSize, current, total } = data || {};
let resData: any = {};
@@ -67,7 +67,7 @@ const ClassDimensionTable: React.FC<Props> = ({ domainManger, dispatch }) => {
};
const queryDataSourceList = async () => {
const { code, data, msg } = await getDatasourceList({ domainId: selectDomainId });
const { code, data, msg } = await getDatasourceList({ modelId });
if (code === 200) {
setDataSourceList(data);
} else {
@@ -77,7 +77,7 @@ const ClassDimensionTable: React.FC<Props> = ({ domainManger, dispatch }) => {
useEffect(() => {
queryDataSourceList();
}, [selectDomainId]);
}, [modelId]);
const columns: ProColumns[] = [
{
@@ -139,7 +139,7 @@ const ClassDimensionTable: React.FC<Props> = ({ domainManger, dispatch }) => {
return (
<Space>
<a
key="classEditBtn"
key="dimensionEditBtn"
onClick={() => {
setDimensionItem(record);
setCreateModalVisible(true);
@@ -148,7 +148,7 @@ const ClassDimensionTable: React.FC<Props> = ({ domainManger, dispatch }) => {
</a>
<a
key="classEditBtn"
key="dimensionValueEditBtn"
onClick={() => {
setDimensionItem(record);
setDimensionValueSettingModalVisible(true);
@@ -176,7 +176,7 @@ const ClassDimensionTable: React.FC<Props> = ({ domainManger, dispatch }) => {
}}
>
<a
key="classEditBtn"
key="dimensionDeleteEditBtn"
onClick={() => {
setDimensionItem(record);
}}
@@ -195,7 +195,6 @@ const ClassDimensionTable: React.FC<Props> = ({ domainManger, dispatch }) => {
<ProTable
className={`${styles.classTable} ${styles.classTableSelectColumnAlignLeft}`}
actionRef={actionRef}
// headerTitle="维度列表"
rowKey="id"
columns={columns}
request={queryDimensionList}
@@ -236,7 +235,7 @@ const ClassDimensionTable: React.FC<Props> = ({ domainManger, dispatch }) => {
{createModalVisible && (
<DimensionInfoModal
domainId={selectDomainId}
modelId={modelId}
bindModalVisible={createModalVisible}
dimensionItem={dimensionItem}
dataSourceList={dataSourceList}
@@ -246,7 +245,7 @@ const ClassDimensionTable: React.FC<Props> = ({ domainManger, dispatch }) => {
dispatch({
type: 'domainManger/queryDimensionList',
payload: {
domainId: selectDomainId,
modelId,
},
});
return;
@@ -269,7 +268,7 @@ const ClassDimensionTable: React.FC<Props> = ({ domainManger, dispatch }) => {
dispatch({
type: 'domainManger/queryDimensionList',
payload: {
domainId: selectDomainId,
modelId,
},
});
setDimensionValueSettingModalVisible(false);

View File

@@ -12,6 +12,7 @@ import MetricInfoCreateForm from './MetricInfoCreateForm';
import moment from 'moment';
import styles from './style.less';
import { ISemantic } from '../data';
type Props = {
dispatch: Dispatch;
@@ -19,9 +20,9 @@ type Props = {
};
const ClassMetricTable: React.FC<Props> = ({ domainManger, dispatch }) => {
const { selectDomainId } = domainManger;
const { selectModelId: modelId, selectDomainId } = domainManger;
const [createModalVisible, setCreateModalVisible] = useState<boolean>(false);
const [metricItem, setMetricItem] = useState<any>();
const [metricItem, setMetricItem] = useState<ISemantic.IMetricItem>();
const [pagination, setPagination] = useState({
current: 1,
pageSize: 20,
@@ -33,7 +34,7 @@ const ClassMetricTable: React.FC<Props> = ({ domainManger, dispatch }) => {
const { code, data, msg } = await queryMetric({
...params,
...pagination,
domainId: selectDomainId,
modelId,
});
const { list, pageSize, current, total } = data || {};
let resData: any = {};
@@ -95,7 +96,6 @@ const ClassMetricTable: React.FC<Props> = ({ domainManger, dispatch }) => {
{
dataIndex: 'type',
title: '指标类型',
// search: false,
valueEnum: {
ATOMIC: '原子指标',
DERIVED: '衍生指标',
@@ -128,7 +128,7 @@ const ClassMetricTable: React.FC<Props> = ({ domainManger, dispatch }) => {
return (
<Space>
<a
key="classEditBtn"
key="metricEditBtn"
onClick={() => {
setMetricItem(record);
setCreateModalVisible(true);
@@ -152,7 +152,7 @@ const ClassMetricTable: React.FC<Props> = ({ domainManger, dispatch }) => {
}}
>
<a
key="classEditBtn"
key="metricDeleteBtn"
onClick={() => {
setMetricItem(record);
}}
@@ -171,7 +171,6 @@ const ClassMetricTable: React.FC<Props> = ({ domainManger, dispatch }) => {
<ProTable
className={`${styles.classTable} ${styles.classTableSelectColumnAlignLeft}`}
actionRef={actionRef}
// headerTitle="指标列表"
rowKey="id"
search={{
span: 4,
@@ -181,7 +180,7 @@ const ClassMetricTable: React.FC<Props> = ({ domainManger, dispatch }) => {
},
}}
columns={columns}
params={{ domainId: selectDomainId }}
params={{ modelId }}
request={queryMetricList}
pagination={pagination}
tableAlertRender={() => {
@@ -212,7 +211,8 @@ const ClassMetricTable: React.FC<Props> = ({ domainManger, dispatch }) => {
/>
{createModalVisible && (
<MetricInfoCreateForm
domainId={Number(selectDomainId)}
domainId={selectDomainId}
modelId={Number(modelId)}
createModalVisible={createModalVisible}
metricItem={metricItem}
onSubmit={() => {
@@ -221,7 +221,7 @@ const ClassMetricTable: React.FC<Props> = ({ domainManger, dispatch }) => {
dispatch({
type: 'domainManger/queryMetricList',
payload: {
domainId: selectDomainId,
modelId,
},
});
}}

View File

@@ -1,7 +1,7 @@
import { useEffect, forwardRef, useImperativeHandle, useState } from 'react';
import type { ForwardRefRenderFunction } from 'react';
import { message, Form, Input, Select, Button, Space } from 'antd';
import { saveDatabase, getDatabaseByDomainId, testDatabaseConnect } from '../../service';
import { saveDatabase, testDatabaseConnect } from '../../service';
import { formLayout } from '@/components/FormHelper/utils';
import styles from '../style.less';

View File

@@ -10,7 +10,7 @@ import { createDimension, updateDimension } from '../service';
import { message } from 'antd';
export type CreateFormProps = {
domainId: number;
modelId: number;
dimensionItem?: ISemantic.IDimensionItem;
onCancel: () => void;
bindModalVisible: boolean;
@@ -24,7 +24,7 @@ const { Option } = Select;
const { TextArea } = Input;
const DimensionInfoModal: React.FC<CreateFormProps> = ({
domainId,
modelId,
onCancel,
bindModalVisible,
dimensionItem,
@@ -55,7 +55,7 @@ const DimensionInfoModal: React.FC<CreateFormProps> = ({
const saveDimension = async (fieldsValue: any, isSilenceSubmit = false) => {
const queryParams = {
domainId,
modelId,
type: 'categorical',
...fieldsValue,
};

View File

@@ -24,7 +24,7 @@ type DomainListProps = {
createDomainBtnVisible?: boolean;
dispatch: Dispatch;
onCreateDomainBtnClick?: () => void;
onTreeSelected?: () => void;
onTreeSelected?: (targetNodeData: ISemantic.IDomainItem) => void;
onTreeDataUpdate?: () => void;
};
@@ -57,7 +57,7 @@ const DomainListTree: FC<DomainListProps> = ({
const [projectInfoParams, setProjectInfoParams] = useState<any>({});
const [filterValue, setFliterValue] = useState<string>('');
const [expandedKeys, setExpandedKeys] = useState<string[]>([]);
const [classList, setClassList] = useState<any[]>([]);
const [classList, setClassList] = useState<ISemantic.IDomainItem[]>([]);
useEffect(() => {
const treeData = addPathInTreeData(constructorClassTreeFromList(domainList));
@@ -77,13 +77,7 @@ const DomainListTree: FC<DomainListProps> = ({
const targetNodeData = classList.filter((item: any) => {
return item.id === selectedKeys;
})[0];
onTreeSelected?.();
dispatch({
type: 'domainManger/setSelectDomain',
selectDomainId: selectedKeys,
selectDomainName: projectName,
domainData: targetNodeData,
});
onTreeSelected?.(targetNodeData);
};
const editProject = async (values: any) => {
@@ -134,7 +128,7 @@ const DomainListTree: FC<DomainListProps> = ({
</span>
{createDomainBtnVisible && (
<span className={styles.operation}>
{Array.isArray(path) && path.length < 3 && (
{Array.isArray(path) && path.length < 2 && (
<PlusOutlined
className={styles.icon}
onClick={() => {

View File

@@ -0,0 +1,135 @@
import { Tabs, Button } from 'antd';
import React from 'react';
import { connect } from 'umi';
import ClassDataSourceTable from './ClassDataSourceTable';
import ClassDimensionTable from './ClassDimensionTable';
import ClassMetricTable from './ClassMetricTable';
import PermissionSection from './Permission/PermissionSection';
import DatabaseSection from './Database/DatabaseSection';
import EntitySettingSection from './Entity/EntitySettingSection';
import OverView from './OverView';
import styles from './style.less';
import type { StateType } from '../model';
import { LeftOutlined } from '@ant-design/icons';
import { ISemantic } from '../data';
import SemanticGraphCanvas from '../SemanticGraphCanvas';
import type { Dispatch } from 'umi';
type Props = {
isModel: boolean;
activeKey: string;
modelList: ISemantic.IModelItem[];
handleModelChange: (model?: ISemantic.IModelItem) => void;
onBackDomainBtnClick?: () => void;
onMenuChange?: (menuKey: string) => void;
domainManger: StateType;
dispatch: Dispatch;
};
const DomainManagerTab: React.FC<Props> = ({
isModel,
activeKey,
modelList,
handleModelChange,
onBackDomainBtnClick,
onMenuChange,
}) => {
const defaultTabKey = 'xflow';
const tabItem = [
{
label: '模型',
key: 'overview',
children: (
<OverView
modelList={modelList}
onModelChange={(model) => {
handleModelChange(model);
}}
/>
),
},
{
label: '数据库',
key: 'dataBase',
children: <DatabaseSection />,
},
{
label: '权限管理',
key: 'permissonSetting',
children: <PermissionSection permissionTarget={'domain'} />,
},
];
const isModelItem = [
{
label: '画布',
key: 'xflow',
children: (
<div style={{ width: '100%', marginTop: -20 }}>
<SemanticGraphCanvas />
</div>
),
},
{
label: '数据源',
key: 'dataSource',
children: <ClassDataSourceTable />,
},
{
label: '维度',
key: 'dimenstion',
children: <ClassDimensionTable />,
},
{
label: '指标',
key: 'metric',
children: <ClassMetricTable />,
},
{
label: '实体',
key: 'entity',
children: <EntitySettingSection />,
},
{
label: '权限管理',
key: 'permissonSetting',
children: <PermissionSection permissionTarget={'model'} />,
},
];
return (
<>
<Tabs
className={styles.tab}
items={!isModel ? tabItem : isModelItem}
activeKey={activeKey || defaultTabKey}
destroyInactiveTabPane
tabBarExtraContent={
isModel ? (
<Button
type="primary"
icon={<LeftOutlined />}
onClick={() => {
onBackDomainBtnClick?.();
}}
style={{ marginRight: 10 }}
>
</Button>
) : undefined
}
onChange={(menuKey: string) => {
onMenuChange?.(menuKey);
}}
/>
</>
);
};
export default connect(({ domainManger }: { domainManger: StateType }) => ({
domainManger,
}))(DomainManagerTab);

View File

@@ -143,7 +143,7 @@ const DefaultSettingForm: ForwardRefRenderFunction<any, Props> = (
};
const { code, msg, data } = await saveDomainExtendQuery({
[chatConfigKey]: params,
domainId,
// domainId,
id,
});
if (code === 200) {

View File

@@ -126,7 +126,7 @@ const DimensionAndMetricVisibleModal: React.FC<Props> = ({
const { code, msg } = await saveDomainExtendQuery({
[chatConfigKey]: params,
domainId,
// domainId,
id,
});
if (code === 200) {

View File

@@ -1,22 +1,22 @@
import { useEffect, useState, forwardRef, useImperativeHandle } from 'react';
import type { ForwardRefRenderFunction } from 'react';
import { message, Form, Input, Select, Button } from 'antd';
import { updateDomain } from '../../service';
import { updateModel } from '../../service';
import type { ISemantic } from '../../data';
import { formLayout } from '@/components/FormHelper/utils';
import styles from '../style.less';
type Props = {
domainData?: ISemantic.IDomainItem;
modelData?: ISemantic.IModelItem;
dimensionList: ISemantic.IDimensionList;
domainId: number;
modelId: number;
onSubmit: () => void;
};
const FormItem = Form.Item;
const EntityCreateForm: ForwardRefRenderFunction<any, Props> = (
{ domainData, dimensionList, domainId, onSubmit },
{ modelData, dimensionList, modelId, onSubmit },
ref,
) => {
const [form] = Form.useForm();
@@ -27,15 +27,15 @@ const EntityCreateForm: ForwardRefRenderFunction<any, Props> = (
useEffect(() => {
form.resetFields();
if (!domainData?.entity) {
if (!modelData?.entity) {
return;
}
const { entity } = domainData;
const { entity } = modelData;
form.setFieldsValue({
...entity,
name: entity.names.join(','),
});
}, [domainData]);
}, [modelData]);
useImperativeHandle(ref, () => ({
getFormValidateFields,
@@ -54,14 +54,14 @@ const EntityCreateForm: ForwardRefRenderFunction<any, Props> = (
const saveEntity = async () => {
const values = await form.validateFields();
const { name } = values;
const { code, msg, data } = await updateDomain({
...domainData,
const { code, msg, data } = await updateModel({
...modelData,
entity: {
...values,
names: name.split(','),
},
id: domainId,
domainId,
id: modelId,
modelId,
});
if (code === 200) {
@@ -79,20 +79,11 @@ const EntityCreateForm: ForwardRefRenderFunction<any, Props> = (
<FormItem hidden={true} name="id" label="ID">
<Input placeholder="id" />
</FormItem>
<FormItem
name="name"
label="实体别名"
// rules={[{ required: true, message: '请输入实体别名' }]}
>
<FormItem name="name" label="实体别名">
<Input placeholder="请输入实体别名,多个名称以英文逗号分隔" />
</FormItem>
<FormItem
name="entityId"
label="唯一标识"
// rules={[{ required: true, message: '请选择实体标识' }]}
>
<FormItem name="entityId" label="唯一标识">
<Select
// mode="multiple"
allowClear
style={{ width: '100%' }}
// filterOption={(inputValue: string, item: any) => {

View File

@@ -22,22 +22,22 @@ const EntitySection: React.FC<Props> = ({
dispatch,
chatConfigType = ChatConfigType.DETAIL,
}) => {
const { selectDomainId, dimensionList, metricList } = domainManger;
const { selectDomainId, selectModelId: modelId, dimensionList, metricList } = domainManger;
const [entityData, setentityData] = useState<IChatConfig.IChatRichConfig>();
const [entityData, setEntityData] = useState<IChatConfig.IChatRichConfig>();
const queryThemeListData: any = async () => {
const { code, data } = await getDomainExtendDetailConfig({
domainId: selectDomainId,
modelId,
});
if (code === 200) {
const { chatAggRichConfig, chatDetailRichConfig, id, domainId } = data;
const { chatAggRichConfig, chatDetailRichConfig, id, domainId, modelId } = data;
if (chatConfigType === ChatConfigType.DETAIL) {
setentityData({ ...chatDetailRichConfig, id, domainId });
setEntityData({ ...chatDetailRichConfig, id, domainId, modelId });
}
if (chatConfigType === ChatConfigType.AGG) {
setentityData({ ...chatAggRichConfig, id, domainId });
setEntityData({ ...chatAggRichConfig, id, domainId, modelId });
}
return;
}
@@ -50,8 +50,11 @@ const EntitySection: React.FC<Props> = ({
};
useEffect(() => {
if (!modelId) {
return;
}
initPage();
}, [selectDomainId]);
}, [modelId]);
return (
<div style={{ width: 800, margin: '0 auto' }}>

View File

@@ -3,7 +3,7 @@ import React, { useState, useEffect, useRef } from 'react';
import type { Dispatch } from 'umi';
import { connect } from 'umi';
import type { StateType } from '../../model';
import { getDomainDetail } from '../../service';
import { getModelDetail } from '../../service';
import ProCard from '@ant-design/pro-card';
import EntityCreateForm from './EntityCreateForm';
import type { ISemantic } from '../../data';
@@ -14,19 +14,19 @@ type Props = {
};
const EntitySettingSection: React.FC<Props> = ({ domainManger }) => {
const { selectDomainId, dimensionList } = domainManger;
const { dimensionList, selectModelId: modelId } = domainManger;
const [domainData, setDomainData] = useState<ISemantic.IDomainItem>();
const [modelData, setModelData] = useState<ISemantic.IModelItem>();
const entityCreateRef = useRef<any>({});
const queryDomainData: any = async () => {
const { code, data } = await getDomainDetail({
domainId: selectDomainId,
const { code, data } = await getModelDetail({
modelId,
});
if (code === 200) {
setDomainData(data);
setModelData(data);
return;
}
@@ -40,7 +40,7 @@ const EntitySettingSection: React.FC<Props> = ({ domainManger }) => {
useEffect(() => {
initPage();
}, [selectDomainId]);
}, [modelId]);
return (
<div style={{ width: 800, margin: '0 auto' }}>
@@ -49,8 +49,8 @@ const EntitySettingSection: React.FC<Props> = ({ domainManger }) => {
<ProCard title="实体" bordered>
<EntityCreateForm
ref={entityCreateRef}
domainId={Number(selectDomainId)}
domainData={domainData}
modelId={Number(modelId)}
modelData={modelData}
dimensionList={dimensionList}
onSubmit={() => {
queryDomainData();

View File

@@ -12,14 +12,14 @@ type Props = {
};
const RecommendedQuestionsSection: React.FC<Props> = ({ domainManger }) => {
const { selectDomainId } = domainManger;
const { selectModelId: modelId } = domainManger;
const [questionData, setQuestionData] = useState<string[]>([]);
const [currentRecordId, setCurrentRecordId] = useState<number>(0);
const queryThemeListData: any = async () => {
const { code, data } = await getDomainExtendConfig({
domainId: selectDomainId,
modelId,
});
if (code === 200) {
@@ -51,7 +51,7 @@ const RecommendedQuestionsSection: React.FC<Props> = ({ domainManger }) => {
return { question };
}),
id: currentRecordId,
domainId: selectDomainId,
modelId,
});
if (code === 200) {
@@ -65,8 +65,11 @@ const RecommendedQuestionsSection: React.FC<Props> = ({ domainManger }) => {
};
useEffect(() => {
if (!modelId) {
return;
}
initPage();
}, [selectDomainId]);
}, [modelId]);
return (
<div style={{ width: 800, margin: '0 auto' }}>

View File

@@ -16,15 +16,15 @@ import { SENSITIVE_LEVEL_OPTIONS } from '../constant';
import { formLayout } from '@/components/FormHelper/utils';
import FormItemTitle from '@/components/FormHelper/FormItemTitle';
import styles from './style.less';
import { getMeasureListByDomainId } from '../service';
import { getMeasureListByModelId } from '../service';
import { creatExprMetric, updateExprMetric } from '../service';
import { ISemantic } from '../data';
import { history } from 'umi';
import { check } from 'prettier';
export type CreateFormProps = {
datasourceId?: number;
domainId: number;
modelId: number;
createModalVisible: boolean;
metricItem: any;
onCancel?: () => void;
@@ -39,6 +39,7 @@ const { Option } = Select;
const MetricInfoCreateForm: React.FC<CreateFormProps> = ({
datasourceId,
domainId,
modelId,
onCancel,
createModalVisible,
metricItem,
@@ -65,7 +66,7 @@ const MetricInfoCreateForm: React.FC<CreateFormProps> = ({
const backward = () => setCurrentStep(currentStep - 1);
const queryClassMeasureList = async () => {
const { code, data } = await getMeasureListByDomainId(domainId);
const { code, data } = await getMeasureListByModelId(modelId);
if (code === 200) {
setClassMeasureList(data);
if (datasourceId) {
@@ -147,7 +148,7 @@ const MetricInfoCreateForm: React.FC<CreateFormProps> = ({
const saveMetric = async (fieldsValue: any) => {
const queryParams = {
domainId,
modelId,
...fieldsValue,
};
const { typeParams } = queryParams;
@@ -351,7 +352,7 @@ const MetricInfoCreateForm: React.FC<CreateFormProps> = ({
type="primary"
key="console"
onClick={() => {
history.replace(`/semanticModel/${domainId}/dataSource`);
history.replace(`/semanticModel/${domainId}/${modelId}/dataSource`);
onCancel?.();
}}
>

View File

@@ -0,0 +1,95 @@
import React, { useState, useEffect } from 'react';
import { Form, Button, Modal, Input, Switch } from 'antd';
import styles from './style.less';
import { message } from 'antd';
import { formLayout } from '@/components/FormHelper/utils';
import { createModel, updateModel } from '../service';
const FormItem = Form.Item;
export type ModelCreateFormModalProps = {
domainId: number;
basicInfo: any;
onCancel: () => void;
onSubmit: (values: any) => void;
};
const ModelCreateFormModal: React.FC<ModelCreateFormModalProps> = (props) => {
const { basicInfo, domainId, onCancel, onSubmit } = props;
const [formVals, setFormVals] = useState<any>(basicInfo);
const [saveLoading, setSaveLoading] = useState(false);
const [form] = Form.useForm();
useEffect(() => {
form.setFieldsValue(basicInfo);
}, [basicInfo]);
const handleConfirm = async () => {
const fieldsValue = await form.validateFields();
const columnsValue = { ...fieldsValue, isUnique: 1, domainId };
const submitData = { ...formVals, ...columnsValue };
setFormVals(submitData);
setSaveLoading(true);
const { code, msg } = await (!submitData.id ? createModel : updateModel)(submitData);
setSaveLoading(false);
if (code === 200) {
onSubmit?.(submitData);
} else {
message.error(msg);
}
};
const footer = (
<>
<Button onClick={onCancel}></Button>
<Button type="primary" loading={saveLoading} onClick={handleConfirm}>
</Button>
</>
);
return (
<Modal
width={640}
bodyStyle={{ padding: '32px 40px 48px' }}
destroyOnClose
title={'模型信息'}
open={true}
footer={footer}
onCancel={onCancel}
>
<Form
{...formLayout}
form={form}
initialValues={{
...formVals,
}}
className={styles.form}
>
<FormItem
name="name"
label="模型名称"
rules={[{ required: true, message: '请输入模型名称!' }]}
>
<Input placeholder="模型名称不可重复" />
</FormItem>
<FormItem
name="bizName"
label="模型英文名称"
rules={[{ required: true, message: '请输入模型英文名称!' }]}
>
<Input placeholder="请输入模型英文名称" />
</FormItem>
<FormItem name="description" label="模型描述">
<Input.TextArea placeholder="模型描述" />
</FormItem>
<FormItem name="isUnique" label="是否唯一" hidden={true}>
<Switch size="small" checked={true} />
</FormItem>
</Form>
</Modal>
);
};
export default ModelCreateFormModal;

View File

@@ -1,23 +1,36 @@
import { CheckCard } from '@ant-design/pro-components';
import React from 'react';
import React, { useState } from 'react';
import { Button, Dropdown, message, Popconfirm } from 'antd';
import { PlusOutlined, EllipsisOutlined } from '@ant-design/icons';
import { ISemantic } from '../data';
import { connect } from 'umi';
import icon from '../../../assets/icon/cloudEditor.svg';
import type { Dispatch } from 'umi';
import type { StateType } from '../model';
import { formatNumber } from '../../../utils/utils';
import { deleteModel } from '../service';
import ModelCreateFormModal from './ModelCreateFormModal';
import styles from './style.less';
type Props = {
modelList: ISemantic.IDomainItem[];
disabledEdit?: boolean;
modelList: ISemantic.IModelItem[];
onModelChange?: (model?: ISemantic.IModelItem) => void;
domainManger: StateType;
dispatch: Dispatch;
};
const OverView: React.FC<Props> = ({ domainManger, dispatch, modelList }) => {
const { selectDomainId } = domainManger;
const OverView: React.FC<Props> = ({
modelList,
disabledEdit = false,
onModelChange,
domainManger,
}) => {
const { selectDomainId, selectModelId } = domainManger;
const [currentModel, setCurrentModel] = useState<any>({});
const [modelCreateFormModalVisible, setModelCreateFormModalVisible] = useState<boolean>(false);
const extraNode = (model: ISemantic.IDomainItem) => {
const descNode = (model: ISemantic.IDomainItem) => {
const { metricCnt, dimensionCnt } = model;
return (
<div className={styles.overviewExtraContainer}>
@@ -40,33 +53,103 @@ const OverView: React.FC<Props> = ({ domainManger, dispatch, modelList }) => {
</div>
);
};
const extraNode = (model: ISemantic.IDomainItem) => {
return (
<Dropdown
placement="top"
menu={{
onClick: ({ key, domEvent }) => {
domEvent.stopPropagation();
if (key === 'edit') {
setCurrentModel(model);
setModelCreateFormModalVisible(true);
}
},
items: [
{
label: '编辑',
key: 'edit',
},
{
label: (
<Popconfirm
title="确认删除?"
okText="是"
cancelText="否"
onConfirm={async () => {
const { code, msg } = await deleteModel(model.id);
if (code === 200) {
onModelChange?.();
} else {
message.error(msg);
}
}}
>
<a key="modelDeleteBtn"></a>
</Popconfirm>
),
key: 'delete',
},
],
}}
>
<EllipsisOutlined
style={{ fontSize: 22, color: 'rgba(0,0,0,0.5)' }}
onClick={(e) => e.stopPropagation()}
/>
</Dropdown>
);
};
return (
<>
<CheckCard.Group value={selectDomainId} defaultValue={selectDomainId}>
<div style={{ padding: '0px 20px 20px' }}>
{!disabledEdit && (
<div style={{ paddingBottom: '20px' }}>
<Button
onClick={() => {
setModelCreateFormModalVisible(true);
}}
type="primary"
>
<PlusOutlined />
</Button>
</div>
)}
<CheckCard.Group value={selectModelId} defaultValue={selectModelId}>
{modelList &&
modelList.map((model: ISemantic.IDomainItem) => {
return (
<CheckCard
avatar={icon}
title={model.name}
title={`${model.name}`}
key={model.id}
value={model.id}
// description={model.description || '模型描述...'}
description={extraNode(model)}
description={descNode(model)}
extra={!disabledEdit && extraNode(model)}
onClick={() => {
const { id, name } = model;
dispatch({
type: 'domainManger/setSelectDomain',
selectDomainId: id,
selectDomainName: name,
domainData: model,
});
onModelChange?.(model);
}}
/>
);
})}
</CheckCard.Group>
</>
{modelCreateFormModalVisible && (
<ModelCreateFormModal
domainId={selectDomainId}
basicInfo={currentModel}
onSubmit={() => {
setModelCreateFormModalVisible(false);
onModelChange?.();
}}
onCancel={() => {
setModelCreateFormModalVisible(false);
}}
/>
)}
</div>
);
};

View File

@@ -6,10 +6,11 @@ import { connect } from 'umi';
import type { Dispatch } from 'umi';
import type { StateType } from '../../model';
import FormItemTitle from '@/components/FormHelper/FormItemTitle';
import { updateDomain, getDomainDetail } from '../../service';
import { updateDomain, updateModel, getDomainDetail, getModelDetail } from '../../service';
import styles from '../style.less';
type Props = {
permissionTarget: 'model' | 'domain';
dispatch: Dispatch;
domainManger: StateType;
onSubmit?: (data?: any) => void;
@@ -18,15 +19,22 @@ type Props = {
const FormItem = Form.Item;
const PermissionAdminForm: React.FC<Props> = ({ domainManger, onValuesChange }) => {
const PermissionAdminForm: React.FC<Props> = ({
permissionTarget,
domainManger,
onValuesChange,
}) => {
const [form] = Form.useForm();
const [isOpenState, setIsOpenState] = useState<boolean>(true);
const [classDetail, setClassDetail] = useState<any>({});
const { selectDomainId } = domainManger;
const { selectModelId: modelId, selectDomainId } = domainManger;
const { APP_TARGET } = process.env;
const queryClassDetail = async (domainId: number) => {
const { code, msg, data } = await getDomainDetail({ domainId });
const queryClassDetail = async () => {
const selectId = permissionTarget === 'model' ? modelId : selectDomainId;
const { code, msg, data } = await (permissionTarget === 'model'
? getModelDetail
: getDomainDetail)({ modelId: selectId });
if (code === 200) {
setClassDetail(data);
const fieldsValue = {
@@ -44,8 +52,8 @@ const PermissionAdminForm: React.FC<Props> = ({ domainManger, onValuesChange })
};
useEffect(() => {
queryClassDetail(selectDomainId);
}, [selectDomainId]);
queryClassDetail();
}, [modelId]);
const saveAuth = async () => {
const values = await form.validateFields();
@@ -57,9 +65,10 @@ const PermissionAdminForm: React.FC<Props> = ({ domainManger, onValuesChange })
viewers,
isOpen: isOpen ? 1 : 0,
};
const { code, msg } = await updateDomain(queryClassData);
const { code, msg } = await (permissionTarget === 'model' ? updateModel : updateDomain)(
queryClassData,
);
if (code === 200) {
// message.success('保存成功');
return;
}
message.error(msg);
@@ -123,16 +132,6 @@ const PermissionAdminForm: React.FC<Props> = ({ domainManger, onValuesChange })
</FormItem>
</>
)}
{/* <FormItem>
<Button
type="primary"
onClick={() => {
saveAuth();
}}
>
保 存
</Button>
</FormItem> */}
</Form>
</>
);

View File

@@ -14,7 +14,6 @@ import styles from '../style.less';
type Props = {
domainManger: StateType;
permissonData: any;
domainId: number;
onCancel: () => void;
visible: boolean;
onSubmit: (params?: any) => void;
@@ -25,11 +24,10 @@ const PermissionCreateDrawer: React.FC<Props> = ({
domainManger,
visible,
permissonData,
domainId,
onCancel,
onSubmit,
}) => {
const { dimensionList, metricList } = domainManger;
const { dimensionList, metricList, selectModelId: modelId } = domainManger;
const [form] = Form.useForm();
const basicInfoFormRef = useRef<any>(null);
const [selectedDimensionKeyList, setSelectedDimensionKeyList] = useState<string[]>([]);
@@ -65,7 +63,7 @@ const PermissionCreateDrawer: React.FC<Props> = ({
metrics: selectedMetricKeyList,
},
],
domainId,
modelId,
});
if (code === 200) {
@@ -136,11 +134,7 @@ const PermissionCreateDrawer: React.FC<Props> = ({
<div style={{ overflow: 'auto', margin: '0 auto', width: '1200px' }}>
<Space direction="vertical" style={{ width: '100%' }} size={20}>
<ProCard title="基本信息" bordered>
<PermissionCreateForm
ref={basicInfoFormRef}
permissonData={permissonData}
domainId={domainId}
/>
<PermissionCreateForm ref={basicInfoFormRef} permissonData={permissonData} />
</ProCard>
<ProCard title="列权限" bordered tooltip="仅对敏感度为高的指标/维度进行授权">

View File

@@ -6,7 +6,6 @@ import SelectTMEPerson from '@/components/SelectTMEPerson';
import { formLayout } from '@/components/FormHelper/utils';
import styles from '../style.less';
type Props = {
domainId: number;
permissonData: any;
onSubmit?: (data?: any) => void;
onValuesChange?: (value, values) => void;

View File

@@ -8,20 +8,20 @@ import PermissionTable from './PermissionTable';
import PermissionAdminForm from './PermissionAdminForm';
type Props = {
permissionTarget: 'model' | 'domain';
dispatch: Dispatch;
domainManger: StateType;
};
const PermissionSection: React.FC<Props> = () => {
const PermissionSection: React.FC<Props> = ({ permissionTarget }) => {
return (
<>
<div>
<Space direction="vertical" style={{ width: '100%' }} size={20}>
<ProCard title="邀请成员" bordered>
<PermissionAdminForm />
<PermissionAdminForm permissionTarget={permissionTarget} />
</ProCard>
<PermissionTable />
{permissionTarget === 'model' && <PermissionTable />}
</Space>
</div>
</>

View File

@@ -19,7 +19,7 @@ type Props = {
const PermissionTable: React.FC<Props> = ({ domainManger }) => {
const { APP_TARGET } = process.env;
const isInner = APP_TARGET === 'inner';
const { dimensionList, metricList, selectDomainId } = domainManger;
const { dimensionList, metricList, selectModelId: modelId } = domainManger;
const [createModalVisible, setCreateModalVisible] = useState<boolean>(false);
const [permissonData, setPermissonData] = useState<any>({});
@@ -37,7 +37,7 @@ const PermissionTable: React.FC<Props> = ({ domainManger }) => {
const actionRef = useRef<ActionType>();
const queryListData = async () => {
const { code, data } = await getGroupAuthInfo(selectDomainId);
const { code, data } = await getGroupAuthInfo(modelId);
if (code === 200) {
setIntentionList(data);
return;
@@ -46,10 +46,10 @@ const PermissionTable: React.FC<Props> = ({ domainManger }) => {
};
useEffect(() => {
if (selectDomainId) {
if (modelId) {
queryListData();
}
}, [selectDomainId]);
}, [modelId]);
const queryDepartmentData = async () => {
const { code, data } = await getOrganizationTree();
@@ -184,7 +184,7 @@ const PermissionTable: React.FC<Props> = ({ domainManger }) => {
return (
<Space>
<a
key="classEditBtn"
key="permissionEditBtn"
onClick={() => {
setPermissonData(record);
setCreateModalVisible(true);
@@ -216,7 +216,7 @@ const PermissionTable: React.FC<Props> = ({ domainManger }) => {
cancelText="否"
onConfirm={async () => {
const { code, msg } = await removeGroupAuth({
domainId: record.domainId,
modelId: record.modelId,
groupId: record.groupId,
});
if (code === 200) {
@@ -228,7 +228,7 @@ const PermissionTable: React.FC<Props> = ({ domainManger }) => {
}}
>
<a
key="classEditBtn"
key="permissionDeleteBtn"
onClick={() => {
setPermissonData(record);
}}
@@ -277,7 +277,6 @@ const PermissionTable: React.FC<Props> = ({ domainManger }) => {
/>
{createModalVisible && (
<PermissionCreateDrawer
domainId={Number(selectDomainId)}
visible={createModalVisible}
permissonData={permissonData}
onSubmit={() => {

View File

@@ -25,7 +25,6 @@ const ProjectInfoForm: React.FC<ProjectInfoFormProps> = (props) => {
const handleConfirm = async () => {
const fieldsValue = await form.validateFields();
// const columnsValue = { ...fieldsValue, isUnique: fieldsValue.isUnique === true ? 1 : 0 };
const columnsValue = { ...fieldsValue, isUnique: 1 };
setFormVals({ ...formVals, ...columnsValue });
setSaveLoading(true);
@@ -97,24 +96,11 @@ const ProjectInfoForm: React.FC<ProjectInfoFormProps> = (props) => {
>
<Input placeholder="请输入主题域英文名称" />
</FormItem>
<FormItem name="description" label="主题域描述">
<FormItem name="description" label="主题域描述" hidden={true}>
<Input.TextArea placeholder="主题域描述" />
</FormItem>
<FormItem name="isUnique" label="是否唯一" hidden={true}>
<Switch
size="small"
checked={true}
// onChange={(checked) => {
// setFormVals({ ...formVals, isUnique: checked });
// }}
/>
{/* <Switch
size="small"
checked={formVals.isUnique ? true : false}
onChange={(checked) => {
setFormVals({ ...formVals, isUnique: checked });
}}
/> */}
<Switch size="small" checked={true} />
</FormItem>
</Form>
</Modal>