mirror of
https://github.com/tencentmusic/supersonic.git
synced 2025-12-13 21:17:08 +00:00
(feature)(webapp) modify model to view (#719)
This commit is contained in:
@@ -28,7 +28,7 @@ export type ModelInfoType = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type EntityInfoType = {
|
export type EntityInfoType = {
|
||||||
modelInfo: ModelInfoType;
|
viewInfo: ModelInfoType;
|
||||||
dimensions: FieldType[];
|
dimensions: FieldType[];
|
||||||
metrics: FieldType[];
|
metrics: FieldType[];
|
||||||
entityId: number;
|
entityId: number;
|
||||||
@@ -83,7 +83,7 @@ export type ChatContextType = {
|
|||||||
aggType: string;
|
aggType: string;
|
||||||
modelId: number;
|
modelId: number;
|
||||||
modelName: string;
|
modelName: string;
|
||||||
model: ModelType;
|
view: ModelType;
|
||||||
dateInfo: DateInfoType;
|
dateInfo: DateInfoType;
|
||||||
dimensions: FieldType[];
|
dimensions: FieldType[];
|
||||||
metrics: FieldType[];
|
metrics: FieldType[];
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ const ParseTip: React.FC<Props> = ({
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
modelId,
|
modelId,
|
||||||
model,
|
view,
|
||||||
dimensions,
|
dimensions,
|
||||||
metrics,
|
metrics,
|
||||||
aggType,
|
aggType,
|
||||||
@@ -148,12 +148,8 @@ const ParseTip: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className={`${prefixCls}-tip-item`}>
|
<div className={`${prefixCls}-tip-item`}>
|
||||||
<div className={`${prefixCls}-tip-item-name`}>数据模型:</div>
|
<div className={`${prefixCls}-tip-item-name`}>数据视图:</div>
|
||||||
<div className={itemValueClass}>
|
<div className={itemValueClass}>{view?.name}</div>
|
||||||
{model?.modelNames?.length === 1
|
|
||||||
? model.modelNames[0]
|
|
||||||
: model?.modelNames?.map(modelName => <Tag key={modelName}>{modelName}</Tag>)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{(queryType === 'METRIC' || queryType === 'METRIC_TAG' || queryType === 'TAG') && (
|
{(queryType === 'METRIC' || queryType === 'METRIC_TAG' || queryType === 'TAG') && (
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ const ChatItem: React.FC<Props> = ({
|
|||||||
let data: MsgDataType | undefined = undefined;
|
let data: MsgDataType | undefined = undefined;
|
||||||
const { queryColumns, queryResults, queryState, queryMode, response, chatContext } =
|
const { queryColumns, queryResults, queryState, queryMode, response, chatContext } =
|
||||||
res.data || {};
|
res.data || {};
|
||||||
if (res.code === 401 || res.code === 412) {
|
if (res.code === 400 || res.code === 401 || res.code === 412) {
|
||||||
tip = res.msg;
|
tip = res.msg;
|
||||||
} else if (res.code !== 200) {
|
} else if (res.code !== 200) {
|
||||||
tip = SEARCH_EXCEPTION_TIP;
|
tip = SEARCH_EXCEPTION_TIP;
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ const BarChart: React.FC<Props> = ({ data, triggerResize, loading, onApplyAuth }
|
|||||||
if (metricColumn && !metricColumn?.authorized) {
|
if (metricColumn && !metricColumn?.authorized) {
|
||||||
return (
|
return (
|
||||||
<NoPermissionChart
|
<NoPermissionChart
|
||||||
model={entityInfo?.modelInfo.name || ''}
|
model={entityInfo?.viewInfo.name || ''}
|
||||||
chartType="barChart"
|
chartType="barChart"
|
||||||
onApplyAuth={onApplyAuth}
|
onApplyAuth={onApplyAuth}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ const MetricCard: React.FC<Props> = ({ data, loading, onApplyAuth }) => {
|
|||||||
<Spin spinning={loading}>
|
<Spin spinning={loading}>
|
||||||
<div className={`${prefixCls}-indicator`}>
|
<div className={`${prefixCls}-indicator`}>
|
||||||
{indicatorColumn && !indicatorColumn?.authorized ? (
|
{indicatorColumn && !indicatorColumn?.authorized ? (
|
||||||
<ApplyAuth model={entityInfo?.modelInfo.name || ''} onApplyAuth={onApplyAuth} />
|
<ApplyAuth model={entityInfo?.viewInfo.name || ''} onApplyAuth={onApplyAuth} />
|
||||||
) : (
|
) : (
|
||||||
<div style={{ display: 'flex', alignItems: 'flex-end' }}>
|
<div style={{ display: 'flex', alignItems: 'flex-end' }}>
|
||||||
<div className={`${prefixCls}-indicator-value`}>
|
<div className={`${prefixCls}-indicator-value`}>
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ const MetricTrend: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<MetricTrendChart
|
<MetricTrendChart
|
||||||
model={entityInfo?.modelInfo.name}
|
model={entityInfo?.viewInfo.name}
|
||||||
dateColumnName={dateColumnName}
|
dateColumnName={dateColumnName}
|
||||||
categoryColumnName={categoryColumnName}
|
categoryColumnName={categoryColumnName}
|
||||||
metricField={currentMetricField}
|
metricField={currentMetricField}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const Table: React.FC<Props> = ({ data, size, loading, onApplyAuth }) => {
|
|||||||
title: name || nameEn,
|
title: name || nameEn,
|
||||||
render: (value: string | number) => {
|
render: (value: string | number) => {
|
||||||
if (!authorized) {
|
if (!authorized) {
|
||||||
return <ApplyAuth model={entityInfo?.modelInfo.name || ''} onApplyAuth={onApplyAuth} />;
|
return <ApplyAuth model={entityInfo?.viewInfo.name || ''} onApplyAuth={onApplyAuth} />;
|
||||||
}
|
}
|
||||||
if (dataFormatType === 'percent') {
|
if (dataFormatType === 'percent') {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
const { createProxyMiddleware } = require('http-proxy-middleware');
|
const { createProxyMiddleware } = require('http-proxy-middleware');
|
||||||
|
|
||||||
module.exports = function(app) {
|
module.exports = function (app) {
|
||||||
app.use(
|
app.use(
|
||||||
'/api',
|
'/api',
|
||||||
createProxyMiddleware({
|
createProxyMiddleware({
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
"lint:style": "stylelint --fix \"src/**/*.less\" --syntax less",
|
"lint:style": "stylelint --fix \"src/**/*.less\" --syntax less",
|
||||||
"precommit": "lint-staged",
|
"precommit": "lint-staged",
|
||||||
"prettier": "prettier -c --write \"src/**/*\"",
|
"prettier": "prettier -c --write \"src/**/*\"",
|
||||||
"start": "npm run start:osdev",
|
"start": "NODE_OPTIONS=--openssl-legacy-provider npm run start:osdev",
|
||||||
"start:dev": "cross-env REACT_APP_ENV=dev MOCK=none APP_TARGET=inner umi dev",
|
"start:dev": "cross-env REACT_APP_ENV=dev MOCK=none APP_TARGET=inner umi dev",
|
||||||
"start:osdev": "cross-env REACT_APP_ENV=dev PORT=9000 MOCK=none APP_TARGET=opensource umi dev",
|
"start:osdev": "cross-env REACT_APP_ENV=dev PORT=9000 MOCK=none APP_TARGET=opensource umi dev",
|
||||||
"start:no-mock": "cross-env MOCK=none umi dev",
|
"start:no-mock": "cross-env MOCK=none umi dev",
|
||||||
|
|||||||
@@ -135,18 +135,6 @@ const AgentsSection: React.FC<Props> = ({
|
|||||||
<PlusOutlined />
|
<PlusOutlined />
|
||||||
新建助理
|
新建助理
|
||||||
</Button>
|
</Button>
|
||||||
<div className={styles.switchShowType}>
|
|
||||||
<span className={styles.switchShowTypeLabel}>切换为卡片</span>
|
|
||||||
<Switch
|
|
||||||
size="small"
|
|
||||||
checked={showType === 'card'}
|
|
||||||
onChange={(value) => {
|
|
||||||
const showTypeValue = value ? 'card' : 'list';
|
|
||||||
setShowType(showTypeValue);
|
|
||||||
localStorage.setItem('AGENT_SHOW_TYPE', showTypeValue);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{showType === 'list' ? (
|
{showType === 'list' ? (
|
||||||
<Table columns={columns} dataSource={showAgents} />
|
<Table columns={columns} dataSource={showAgents} />
|
||||||
|
|||||||
@@ -1,18 +1,16 @@
|
|||||||
import { Form, Modal, Input, Select, Button } from 'antd';
|
import { Form, Modal, Input, Select, Button, TreeSelect } from 'antd';
|
||||||
import {
|
import {
|
||||||
AgentToolType,
|
AgentToolType,
|
||||||
AgentToolTypeEnum,
|
AgentToolTypeEnum,
|
||||||
AGENT_TOOL_TYPE_LIST,
|
AGENT_TOOL_TYPE_LIST,
|
||||||
MetricOptionType,
|
MetricOptionType,
|
||||||
MetricType,
|
|
||||||
ModelType,
|
|
||||||
QUERY_MODE_LIST,
|
QUERY_MODE_LIST,
|
||||||
} from './type';
|
} from './type';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { DeleteOutlined, PlusOutlined } from '@ant-design/icons';
|
import { DeleteOutlined, PlusOutlined } from '@ant-design/icons';
|
||||||
import styles from './style.less';
|
import styles from './style.less';
|
||||||
import { getLeafList, uuid } from '@/utils/utils';
|
import { traverseTree, uuid } from '@/utils/utils';
|
||||||
import { getMetricList, getModelList } from './service';
|
import { getModelList } from './service';
|
||||||
import { PluginType } from '../ChatPlugin/type';
|
import { PluginType } from '../ChatPlugin/type';
|
||||||
import { getPluginList } from '../ChatPlugin/service';
|
import { getPluginList } from '../ChatPlugin/service';
|
||||||
|
|
||||||
@@ -26,17 +24,22 @@ type Props = {
|
|||||||
|
|
||||||
const ToolModal: React.FC<Props> = ({ editTool, onSaveTool, onCancel }) => {
|
const ToolModal: React.FC<Props> = ({ editTool, onSaveTool, onCancel }) => {
|
||||||
const [toolType, setToolType] = useState<AgentToolTypeEnum>();
|
const [toolType, setToolType] = useState<AgentToolTypeEnum>();
|
||||||
const [modelList, setModelList] = useState<ModelType[]>([]);
|
const [modelList, setModelList] = useState<any[]>([]);
|
||||||
const [saveLoading, setSaveLoading] = useState(false);
|
const [saveLoading, setSaveLoading] = useState(false);
|
||||||
const [examples, setExamples] = useState<{ id: string; question?: string }[]>([]);
|
const [examples, setExamples] = useState<{ id: string; question?: string }[]>([]);
|
||||||
const [metricOptions, setMetricOptions] = useState<MetricOptionType[]>([]);
|
const [metricOptions, setMetricOptions] = useState<MetricOptionType[]>([]);
|
||||||
const [modelMetricList, setModelMetricList] = useState<MetricType[]>([]);
|
|
||||||
const [plugins, setPlugins] = useState<PluginType[]>([]);
|
const [plugins, setPlugins] = useState<PluginType[]>([]);
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
const initModelList = async () => {
|
const initModelList = async () => {
|
||||||
const res = await getModelList();
|
const res = await getModelList();
|
||||||
setModelList([{ id: -1, name: '默认' }, ...getLeafList(res.data)]);
|
const treeData = traverseTree(res.data, (node: any) => {
|
||||||
|
node.title = node.name;
|
||||||
|
node.value = node.type === 'DOMAIN' ? `DOMAIN_${node.id}` : node.id;
|
||||||
|
node.checkable =
|
||||||
|
node.type === 'VIEW' || (node.type === 'DOMAIN' && node.children?.length > 0);
|
||||||
|
});
|
||||||
|
setModelList([{ title: '默认', value: -1, type: 'VIEW' }, ...treeData]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const initPluginList = async () => {
|
const initPluginList = async () => {
|
||||||
@@ -49,11 +52,6 @@ const ToolModal: React.FC<Props> = ({ editTool, onSaveTool, onCancel }) => {
|
|||||||
initPluginList();
|
initPluginList();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const initModelMetrics = async (params: any) => {
|
|
||||||
const res = await getMetricList(params[0].modelId);
|
|
||||||
setModelMetricList(res.data.list);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (editTool) {
|
if (editTool) {
|
||||||
form.setFieldsValue({ ...editTool, plugins: editTool.plugins?.[0] });
|
form.setFieldsValue({ ...editTool, plugins: editTool.plugins?.[0] });
|
||||||
@@ -62,9 +60,6 @@ const ToolModal: React.FC<Props> = ({ editTool, onSaveTool, onCancel }) => {
|
|||||||
(editTool.exampleQuestions || []).map((item) => ({ id: uuid(), question: item })),
|
(editTool.exampleQuestions || []).map((item) => ({ id: uuid(), question: item })),
|
||||||
);
|
);
|
||||||
setMetricOptions(editTool.metricOptions || []);
|
setMetricOptions(editTool.metricOptions || []);
|
||||||
if (editTool.metricOptions && editTool.metricOptions.length > 0) {
|
|
||||||
initModelMetrics(editTool.metricOptions || []);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
}
|
}
|
||||||
@@ -88,11 +83,6 @@ const ToolModal: React.FC<Props> = ({ editTool, onSaveTool, onCancel }) => {
|
|||||||
setSaveLoading(false);
|
setSaveLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateMetricList = async (value: number) => {
|
|
||||||
const res = await getMetricList(value);
|
|
||||||
setModelMetricList(res.data.list);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
open
|
open
|
||||||
@@ -115,11 +105,13 @@ const ToolModal: React.FC<Props> = ({ editTool, onSaveTool, onCancel }) => {
|
|||||||
</FormItem>
|
</FormItem>
|
||||||
{(toolType === AgentToolTypeEnum.NL2SQL_RULE ||
|
{(toolType === AgentToolTypeEnum.NL2SQL_RULE ||
|
||||||
toolType === AgentToolTypeEnum.NL2SQL_LLM) && (
|
toolType === AgentToolTypeEnum.NL2SQL_LLM) && (
|
||||||
<FormItem name="modelIds" label="主题域">
|
<FormItem name="viewIds" label="视图">
|
||||||
<Select
|
<TreeSelect
|
||||||
options={modelList.map((model) => ({ label: model.name, value: model.id }))}
|
treeData={modelList}
|
||||||
placeholder="请选择主题域"
|
placeholder="请选择视图"
|
||||||
mode="multiple"
|
multiple
|
||||||
|
treeCheckable
|
||||||
|
allowClear
|
||||||
/>
|
/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
@@ -159,70 +151,6 @@ const ToolModal: React.FC<Props> = ({ editTool, onSaveTool, onCancel }) => {
|
|||||||
</div>
|
</div>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
{toolType === AgentToolTypeEnum.ANALYTICS && (
|
|
||||||
<>
|
|
||||||
<FormItem name="modelId" label="主题域">
|
|
||||||
<Select
|
|
||||||
options={modelList.map((model) => ({ label: model.name, value: model.id }))}
|
|
||||||
showSearch
|
|
||||||
filterOption={(input, option) =>
|
|
||||||
((option?.label ?? '') as string).toLowerCase().includes(input.toLowerCase())
|
|
||||||
}
|
|
||||||
placeholder="请选择主题域"
|
|
||||||
onChange={(value) => {
|
|
||||||
setMetricOptions([...metricOptions]);
|
|
||||||
updateMetricList(value);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</FormItem>
|
|
||||||
<FormItem name="params" label="指标">
|
|
||||||
<div className={styles.paramsSection}>
|
|
||||||
{metricOptions.map((filter: any) => {
|
|
||||||
return (
|
|
||||||
<div className={styles.filterRow} key={filter.id}>
|
|
||||||
<Select
|
|
||||||
placeholder="请选择指标,需先选择主题域"
|
|
||||||
options={(modelMetricList || []).map((metric) => ({
|
|
||||||
label: metric.name,
|
|
||||||
value: `${metric.id}`,
|
|
||||||
}))}
|
|
||||||
showSearch
|
|
||||||
className={styles.filterParamValueField}
|
|
||||||
filterOption={(input, option) =>
|
|
||||||
((option?.label ?? '') as string)
|
|
||||||
.toLowerCase()
|
|
||||||
.includes(input.toLowerCase())
|
|
||||||
}
|
|
||||||
allowClear
|
|
||||||
value={filter.metricId}
|
|
||||||
onChange={(value) => {
|
|
||||||
filter.metricId = value;
|
|
||||||
setMetricOptions([...metricOptions]);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<DeleteOutlined
|
|
||||||
onClick={() => {
|
|
||||||
setMetricOptions(metricOptions.filter((item) => item.id !== filter.id));
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
<Button
|
|
||||||
onClick={() => {
|
|
||||||
setMetricOptions([
|
|
||||||
...metricOptions,
|
|
||||||
{ id: uuid(), metricId: undefined, modelId: undefined },
|
|
||||||
]);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<PlusOutlined />
|
|
||||||
新增指标
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</FormItem>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{toolType === AgentToolTypeEnum.PLUGIN && (
|
{toolType === AgentToolTypeEnum.PLUGIN && (
|
||||||
<FormItem name="plugins" label="插件">
|
<FormItem name="plugins" label="插件">
|
||||||
<Select
|
<Select
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export function deleteAgent(id: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getModelList() {
|
export function getModelList() {
|
||||||
return request<Result<ModelType[]>>('/api/chat/conf/viewList', {
|
return request<Result<ModelType[]>>('/api/chat/conf/getDomainViewTree', {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ export enum AgentToolTypeEnum {
|
|||||||
NL2SQL_RULE = 'NL2SQL_RULE',
|
NL2SQL_RULE = 'NL2SQL_RULE',
|
||||||
NL2SQL_LLM = 'NL2SQL_LLM',
|
NL2SQL_LLM = 'NL2SQL_LLM',
|
||||||
PLUGIN = 'PLUGIN',
|
PLUGIN = 'PLUGIN',
|
||||||
ANALYTICS = 'ANALYTICS',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AGENT_TOOL_TYPE_LIST = [
|
export const AGENT_TOOL_TYPE_LIST = [
|
||||||
@@ -76,6 +75,7 @@ export type ModelType = {
|
|||||||
parentId: number;
|
parentId: number;
|
||||||
name: string;
|
name: string;
|
||||||
bizName: string;
|
bizName: string;
|
||||||
|
type: 'DOMAIN' | 'VIEW';
|
||||||
};
|
};
|
||||||
|
|
||||||
export type MetricType = {
|
export type MetricType = {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Modal, Select, Form, Input, InputNumber, message, Button, Radio } from 'antd';
|
import { Modal, Select, Form, Input, InputNumber, message, Button, Radio, TreeSelect } from 'antd';
|
||||||
import { getDimensionList, getModelList, savePlugin } from './service';
|
import { getDimensionList, getModelList, savePlugin } from './service';
|
||||||
import {
|
import {
|
||||||
DimensionType,
|
DimensionType,
|
||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
FunctionParamFormItemType,
|
FunctionParamFormItemType,
|
||||||
PluginTypeEnum,
|
PluginTypeEnum,
|
||||||
} from './type';
|
} from './type';
|
||||||
import { getLeafList, uuid } from '@/utils/utils';
|
import { getLeafList, traverseTree, uuid } from '@/utils/utils';
|
||||||
import styles from './style.less';
|
import styles from './style.less';
|
||||||
import { PLUGIN_TYPE_MAP } from './constants';
|
import { PLUGIN_TYPE_MAP } from './constants';
|
||||||
import { DeleteOutlined, PlusOutlined } from '@ant-design/icons';
|
import { DeleteOutlined, PlusOutlined } from '@ant-design/icons';
|
||||||
@@ -38,7 +38,13 @@ const DetailModal: React.FC<Props> = ({ detail, onSubmit, onCancel }) => {
|
|||||||
|
|
||||||
const initModelList = async () => {
|
const initModelList = async () => {
|
||||||
const res = await getModelList();
|
const res = await getModelList();
|
||||||
setModelList([{ id: -1, name: '默认' }, ...getLeafList(res.data)]);
|
const treeData = traverseTree(res.data, (node: any) => {
|
||||||
|
node.title = node.name;
|
||||||
|
node.value = node.type === 'DOMAIN' ? `DOMAIN_${node.id}` : node.id;
|
||||||
|
node.checkable =
|
||||||
|
node.type === 'VIEW' || (node.type === 'DOMAIN' && node.children?.length > 0);
|
||||||
|
});
|
||||||
|
setModelList([{ title: '默认', value: -1, type: 'VIEW' }, ...treeData]);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -181,18 +187,12 @@ const DetailModal: React.FC<Props> = ({ detail, onSubmit, onCancel }) => {
|
|||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
>
|
>
|
||||||
<Form {...layout} form={form} style={{ maxWidth: 820 }}>
|
<Form {...layout} form={form} style={{ maxWidth: 820 }}>
|
||||||
<FormItem name="modelList" label="主题域">
|
<FormItem name="viewList" label="视图">
|
||||||
<Select
|
<TreeSelect
|
||||||
placeholder="请选择主题域"
|
treeData={modelList}
|
||||||
options={modelList.map((model) => ({
|
placeholder="请选择视图"
|
||||||
label: model.name,
|
multiple
|
||||||
value: model.id,
|
treeCheckable
|
||||||
}))}
|
|
||||||
showSearch
|
|
||||||
filterOption={(input, option) =>
|
|
||||||
((option?.label ?? '') as string).toLowerCase().includes(input.toLowerCase())
|
|
||||||
}
|
|
||||||
mode="multiple"
|
|
||||||
allowClear
|
allowClear
|
||||||
/>
|
/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ import { PlusOutlined } from '@ant-design/icons';
|
|||||||
import { Button, Input, message, Popconfirm, Select, Table, Tag } from 'antd';
|
import { Button, Input, message, Popconfirm, Select, Table, Tag } from 'antd';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { PARSE_MODE_MAP, PLUGIN_TYPE_MAP } from './constants';
|
import { PLUGIN_TYPE_MAP } from './constants';
|
||||||
import DetailModal from './DetailModal';
|
import DetailModal from './DetailModal';
|
||||||
import { deletePlugin, getModelList, getPluginList } from './service';
|
import { deletePlugin, getModelList, getPluginList } from './service';
|
||||||
import styles from './style.less';
|
import styles from './style.less';
|
||||||
import { ModelType, ParseModeEnum, PluginType, PluginTypeEnum } from './type';
|
import { ModelType, PluginType, PluginTypeEnum } from './type';
|
||||||
|
|
||||||
const { Search } = Input;
|
const { Search } = Input;
|
||||||
|
|
||||||
@@ -57,9 +57,9 @@ const PluginManage = () => {
|
|||||||
key: 'name',
|
key: 'name',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '主题域',
|
title: '视图',
|
||||||
dataIndex: 'modelList',
|
dataIndex: 'viewList',
|
||||||
key: 'modelList',
|
key: 'viewList',
|
||||||
width: 200,
|
width: 200,
|
||||||
render: (value: number[]) => {
|
render: (value: number[]) => {
|
||||||
if (value?.includes(-1)) {
|
if (value?.includes(-1)) {
|
||||||
@@ -67,7 +67,7 @@ const PluginManage = () => {
|
|||||||
}
|
}
|
||||||
return value ? (
|
return value ? (
|
||||||
<div className={styles.modelColumn}>
|
<div className={styles.modelColumn}>
|
||||||
{value.map((id, index) => {
|
{value.map((id) => {
|
||||||
const name = modelList.find((model) => model.id === +id)?.name;
|
const name = modelList.find((model) => model.id === +id)?.name;
|
||||||
return name ? <Tag key={id}>{name}</Tag> : null;
|
return name ? <Tag key={id}>{name}</Tag> : null;
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export function deletePlugin(id: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getModelList() {
|
export function getModelList() {
|
||||||
return request<Result<ModelType[]>>('/api/chat/conf/viewList', {
|
return request<Result<ModelType[]>>('/api/chat/conf/getDomainViewTree', {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -371,7 +371,7 @@ function getLeafNodes(treeNodes: any[]): any[] {
|
|||||||
return leafNodes;
|
return leafNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildTree(nodes: any[]): any[] {
|
export function buildTree(nodes: any[]): any[] {
|
||||||
const map: Record<number, any> = {};
|
const map: Record<number, any> = {};
|
||||||
const roots: any[] = [];
|
const roots: any[] = [];
|
||||||
|
|
||||||
@@ -400,6 +400,16 @@ export function getLeafList(flatNodes: any[]): any[] {
|
|||||||
return leafNodes;
|
return leafNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function traverseTree(treeData: any[], callback: (node: any) => void) {
|
||||||
|
treeData.forEach((node) => {
|
||||||
|
callback(node);
|
||||||
|
if (node.children?.length > 0) {
|
||||||
|
traverseTree(node.children, callback);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return treeData;
|
||||||
|
}
|
||||||
|
|
||||||
export function traverseRoutes(routes, env: string, result: any[] = []) {
|
export function traverseRoutes(routes, env: string, result: any[] = []) {
|
||||||
if (!Array.isArray(routes)) {
|
if (!Array.isArray(routes)) {
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
Reference in New Issue
Block a user