mirror of
https://github.com/tencentmusic/supersonic.git
synced 2025-12-15 06:27:21 +00:00
[feature](webapp) add copilot and modify domain to model
This commit is contained in:
@@ -22,7 +22,7 @@ module.exports = function (proxy, allowedHost) {
|
||||
// https://github.com/webpack/webpack-dev-server/issues/887
|
||||
// https://medium.com/webpack/webpack-dev-server-middleware-security-issues-1489d950874a
|
||||
// However, it made several existing use cases such as development in cloud
|
||||
// environment or subdomains in development significantly more complicated:
|
||||
// environment or submodels in development significantly more complicated:
|
||||
// https://github.com/facebook/create-react-app/issues/2271
|
||||
// https://github.com/facebook/create-react-app/issues/2233
|
||||
// While we're investigating better solutions, for now we will take a
|
||||
@@ -33,7 +33,7 @@ module.exports = function (proxy, allowedHost) {
|
||||
// So we will disable the host check normally, but enable it if you have
|
||||
// specified the `proxy` setting. Finally, we let you override it if you
|
||||
// really know what you're doing with a special environment variable.
|
||||
// Note: ["localhost", ".localhost"] will support subdomains - but we might
|
||||
// Note: ["localhost", ".localhost"] will support submodels - but we might
|
||||
// want to allow setting the allowedHosts manually for more complex setups
|
||||
allowedHosts: disableFirewall ? 'all' : [allowedHost],
|
||||
headers: {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export type SearchRecommendItem = {
|
||||
complete: boolean;
|
||||
domainId: number;
|
||||
domainName: string;
|
||||
modelId: number;
|
||||
modelName: string;
|
||||
recommend: string;
|
||||
subRecommend: string;
|
||||
schemaElementType: string;
|
||||
@@ -12,12 +12,12 @@ export type FieldType = {
|
||||
id: number;
|
||||
name: string;
|
||||
status: number;
|
||||
domain: number;
|
||||
model: number;
|
||||
type: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export type DomainInfoType = {
|
||||
export type ModelInfoType = {
|
||||
bizName: string;
|
||||
itemId: number;
|
||||
name: string;
|
||||
@@ -27,7 +27,7 @@ export type DomainInfoType = {
|
||||
};
|
||||
|
||||
export type EntityInfoType = {
|
||||
domainInfo: DomainInfoType;
|
||||
modelInfo: ModelInfoType;
|
||||
dimensions: FieldType[];
|
||||
metrics: FieldType[];
|
||||
entityId: number;
|
||||
@@ -53,8 +53,8 @@ export type FilterItemType = {
|
||||
|
||||
export type ChatContextType = {
|
||||
aggType: string;
|
||||
domainId: number;
|
||||
domainName: string;
|
||||
modelId: number;
|
||||
modelName: string;
|
||||
dateInfo: DateInfoType;
|
||||
dimensions: FieldType[];
|
||||
metrics: FieldType[];
|
||||
@@ -104,6 +104,7 @@ export type MsgDataType = {
|
||||
queryMode: string;
|
||||
queryState: string;
|
||||
response: PluginResonseType;
|
||||
parseOptions?: ChatContextType[];
|
||||
};
|
||||
|
||||
export enum ParseStateEnum {
|
||||
@@ -121,6 +122,7 @@ export type ParseDataType = {
|
||||
}
|
||||
|
||||
export type QueryDataType = {
|
||||
aggregateInfo: AggregateInfoType;
|
||||
queryColumns: ColumnType[];
|
||||
queryResults: any[];
|
||||
};
|
||||
@@ -153,7 +155,7 @@ export const SEMANTIC_TYPE_MAP = {
|
||||
};
|
||||
|
||||
export type SuggestionItemType = {
|
||||
domain: number;
|
||||
model: number;
|
||||
name: string;
|
||||
bizName: string
|
||||
};
|
||||
@@ -187,7 +189,7 @@ export type HistoryType = {
|
||||
|
||||
export type DrillDownDimensionType = {
|
||||
id: number;
|
||||
domain: number;
|
||||
model: number;
|
||||
name: string;
|
||||
bizName: string;
|
||||
}
|
||||
@@ -10,6 +10,7 @@ type Props = {
|
||||
parseInfoOptions: ChatContextType[];
|
||||
parseTip: string;
|
||||
currentParseInfo?: ChatContextType;
|
||||
optionMode?: boolean;
|
||||
onSelectParseInfo: (parseInfo: ChatContextType) => void;
|
||||
};
|
||||
|
||||
@@ -20,6 +21,7 @@ const ParseTip: React.FC<Props> = ({
|
||||
parseInfoOptions,
|
||||
parseTip,
|
||||
currentParseInfo,
|
||||
optionMode,
|
||||
onSelectParseInfo,
|
||||
}) => {
|
||||
const prefixCls = `${PREFIX_CLS}-item`;
|
||||
@@ -38,7 +40,7 @@ const ParseTip: React.FC<Props> = ({
|
||||
|
||||
const getTipNode = (parseInfo: ChatContextType, isOptions?: boolean, index?: number) => {
|
||||
const {
|
||||
domainName,
|
||||
modelName,
|
||||
dateInfo,
|
||||
dimensionFilters,
|
||||
dimensions,
|
||||
@@ -70,6 +72,7 @@ const ParseTip: React.FC<Props> = ({
|
||||
[`${prefixCls}-tip-item-option`]: isOptions,
|
||||
});
|
||||
|
||||
const entityId = dimensionFilters?.length > 0 ? dimensionFilters[0].value : undefined;
|
||||
const entityAlias = entity?.alias?.[0]?.split('.')?.[0];
|
||||
const entityName = elementMatches?.find(item => item.element?.type === 'ID')?.element.name;
|
||||
|
||||
@@ -106,7 +109,10 @@ const ParseTip: React.FC<Props> = ({
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{queryMode === 'METRIC_ENTITY' || queryMode === 'ENTITY_DETAIL' ? (
|
||||
{queryMode.includes('ENTITY') &&
|
||||
typeof entityId === 'string' &&
|
||||
!!entityAlias &&
|
||||
!!entityName ? (
|
||||
<div className={`${prefixCls}-tip-item`}>
|
||||
<div className={`${prefixCls}-tip-item-name`}>{entityAlias}:</div>
|
||||
<div className={itemValueClass}>{entityName}</div>
|
||||
@@ -114,7 +120,7 @@ const ParseTip: React.FC<Props> = ({
|
||||
) : (
|
||||
<div className={`${prefixCls}-tip-item`}>
|
||||
<div className={`${prefixCls}-tip-item-name`}>主题域:</div>
|
||||
<div className={itemValueClass}>{domainName}</div>
|
||||
<div className={itemValueClass}>{modelName}</div>
|
||||
</div>
|
||||
)}
|
||||
{modeName === '算指标' && metric && (
|
||||
@@ -180,10 +186,12 @@ const ParseTip: React.FC<Props> = ({
|
||||
|
||||
let tipNode: ReactNode;
|
||||
|
||||
if (parseInfoOptions.length > 1) {
|
||||
if (parseInfoOptions.length > 1 || optionMode) {
|
||||
tipNode = (
|
||||
<div className={`${prefixCls}-multi-options`}>
|
||||
<div>您的问题解析为以下几项,请您点击确认</div>
|
||||
<div>
|
||||
还有以下的相关问题,<strong>请您点击提交</strong>
|
||||
</div>
|
||||
<div className={`${prefixCls}-options`}>
|
||||
{parseInfoOptions.map((item, index) => getTipNode(item, true, index))}
|
||||
</div>
|
||||
|
||||
@@ -9,12 +9,13 @@ import ExecuteItem from './ExecuteItem';
|
||||
type Props = {
|
||||
msg: string;
|
||||
conversationId?: number;
|
||||
domainId?: number;
|
||||
modelId?: number;
|
||||
filter?: any[];
|
||||
isLastMessage?: boolean;
|
||||
msgData?: MsgDataType;
|
||||
isMobileMode?: boolean;
|
||||
triggerResize?: boolean;
|
||||
parseOptions?: ChatContextType[];
|
||||
onMsgDataLoaded?: (data: MsgDataType, valid: boolean) => void;
|
||||
onUpdateMessageScroll?: () => void;
|
||||
};
|
||||
@@ -22,19 +23,20 @@ type Props = {
|
||||
const ChatItem: React.FC<Props> = ({
|
||||
msg,
|
||||
conversationId,
|
||||
domainId,
|
||||
modelId,
|
||||
filter,
|
||||
isLastMessage,
|
||||
isMobileMode,
|
||||
triggerResize,
|
||||
msgData,
|
||||
parseOptions,
|
||||
onMsgDataLoaded,
|
||||
onUpdateMessageScroll,
|
||||
}) => {
|
||||
const [data, setData] = useState<MsgDataType>();
|
||||
const [parseLoading, setParseLoading] = useState(false);
|
||||
const [parseInfo, setParseInfo] = useState<ChatContextType>();
|
||||
const [parseInfoOptions, setParseInfoOptions] = useState<ChatContextType[]>([]);
|
||||
const [parseInfoOptions, setParseInfoOptions] = useState<ChatContextType[]>(parseOptions || []);
|
||||
const [parseTip, setParseTip] = useState('');
|
||||
const [executeLoading, setExecuteLoading] = useState(false);
|
||||
const [executeTip, setExecuteTip] = useState('');
|
||||
@@ -68,20 +70,43 @@ const ChatItem: React.FC<Props> = ({
|
||||
return true;
|
||||
};
|
||||
|
||||
const onExecute = async (parseInfoValue: ChatContextType, isSwitch?: boolean) => {
|
||||
const onExecute = async (
|
||||
parseInfoValue: ChatContextType,
|
||||
parseInfoOptions?: ChatContextType[]
|
||||
) => {
|
||||
setExecuteMode(true);
|
||||
setExecuteLoading(true);
|
||||
const { data } = await chatExecute(msg, conversationId!, parseInfoValue);
|
||||
setExecuteLoading(false);
|
||||
const valid = updateData(data);
|
||||
if (onMsgDataLoaded && !isSwitch) {
|
||||
onMsgDataLoaded({ ...data.data, chatContext: parseInfoValue }, valid);
|
||||
if (onMsgDataLoaded) {
|
||||
let parseOptions: ChatContextType[] = parseInfoOptions || [];
|
||||
if (
|
||||
parseInfoOptions &&
|
||||
parseInfoOptions.length > 1 &&
|
||||
(parseInfoOptions[0].queryMode.includes('METRIC') ||
|
||||
parseInfoOptions[0].queryMode.includes('ENTITY'))
|
||||
) {
|
||||
parseOptions = parseInfoOptions.filter(
|
||||
(item, index) =>
|
||||
index === 0 ||
|
||||
(!item.queryMode.includes('METRIC') && !item.queryMode.includes('ENTITY'))
|
||||
);
|
||||
}
|
||||
onMsgDataLoaded(
|
||||
{
|
||||
...data.data,
|
||||
chatContext: parseInfoValue,
|
||||
parseOptions: parseOptions.length > 1 ? parseOptions.slice(1) : undefined,
|
||||
},
|
||||
valid
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const onSendMsg = async () => {
|
||||
setParseLoading(true);
|
||||
const { data: parseData } = await chatParse(msg, conversationId, domainId, filter);
|
||||
const { data: parseData } = await chatParse(msg, conversationId, modelId, filter);
|
||||
setParseLoading(false);
|
||||
const { code, data } = parseData || {};
|
||||
const { state, selectedParses } = data || {};
|
||||
@@ -91,7 +116,7 @@ const ChatItem: React.FC<Props> = ({
|
||||
selectedParses == null ||
|
||||
selectedParses.length === 0 ||
|
||||
(selectedParses.length === 1 &&
|
||||
!selectedParses[0]?.domainName &&
|
||||
!selectedParses[0]?.modelName &&
|
||||
!selectedParses[0]?.properties?.CONTEXT?.plugin?.name &&
|
||||
selectedParses[0]?.queryMode !== 'WEB_PAGE')
|
||||
) {
|
||||
@@ -102,15 +127,13 @@ const ChatItem: React.FC<Props> = ({
|
||||
onUpdateMessageScroll();
|
||||
}
|
||||
setParseInfoOptions(selectedParses || []);
|
||||
if (selectedParses.length === 1) {
|
||||
const parseInfoValue = selectedParses[0];
|
||||
setParseInfo(parseInfoValue);
|
||||
onExecute(parseInfoValue);
|
||||
}
|
||||
const parseInfoValue = selectedParses[0];
|
||||
setParseInfo(parseInfoValue);
|
||||
onExecute(parseInfoValue, selectedParses);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (data !== undefined) {
|
||||
if (data !== undefined || parseOptions !== undefined || executeTip !== '') {
|
||||
return;
|
||||
}
|
||||
if (msgData) {
|
||||
@@ -124,7 +147,7 @@ const ChatItem: React.FC<Props> = ({
|
||||
|
||||
const onSwitchEntity = async (entityId: string) => {
|
||||
setEntitySwitching(true);
|
||||
const res = await switchEntity(entityId, data?.chatContext?.domainId, conversationId || 0);
|
||||
const res = await switchEntity(entityId, data?.chatContext?.modelId, conversationId || 0);
|
||||
setEntitySwitching(false);
|
||||
setData(res.data.data);
|
||||
};
|
||||
@@ -135,7 +158,7 @@ const ChatItem: React.FC<Props> = ({
|
||||
|
||||
const onSelectParseInfo = async (parseInfoValue: ChatContextType) => {
|
||||
setParseInfo(parseInfoValue);
|
||||
onExecute(parseInfoValue, parseInfo !== undefined);
|
||||
onExecute(parseInfoValue);
|
||||
if (onUpdateMessageScroll) {
|
||||
onUpdateMessageScroll();
|
||||
}
|
||||
@@ -148,9 +171,10 @@ const ChatItem: React.FC<Props> = ({
|
||||
<div className={`${prefixCls}-content`}>
|
||||
<ParseTip
|
||||
parseLoading={parseLoading}
|
||||
parseInfoOptions={parseInfoOptions}
|
||||
parseInfoOptions={parseOptions || parseInfoOptions.slice(0, 1)}
|
||||
parseTip={parseTip}
|
||||
currentParseInfo={parseInfo}
|
||||
optionMode={parseOptions !== undefined}
|
||||
onSelectParseInfo={onSelectParseInfo}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { PREFIX_CLS } from '../../../common/constants';
|
||||
|
||||
type Props = {
|
||||
domain: string;
|
||||
onApplyAuth?: (domain: string) => void;
|
||||
model: string;
|
||||
onApplyAuth?: (model: string) => void;
|
||||
};
|
||||
|
||||
const ApplyAuth: React.FC<Props> = ({ domain, onApplyAuth }) => {
|
||||
const ApplyAuth: React.FC<Props> = ({ model, onApplyAuth }) => {
|
||||
const prefixCls = `${PREFIX_CLS}-apply-auth`;
|
||||
|
||||
return (
|
||||
@@ -15,7 +15,7 @@ const ApplyAuth: React.FC<Props> = ({ domain, onApplyAuth }) => {
|
||||
<span
|
||||
className={`${prefixCls}-apply`}
|
||||
onClick={() => {
|
||||
onApplyAuth(domain);
|
||||
onApplyAuth(model);
|
||||
}}
|
||||
>
|
||||
点击申请
|
||||
|
||||
@@ -15,7 +15,7 @@ type Props = {
|
||||
drillDownDimension?: DrillDownDimensionType;
|
||||
loading: boolean;
|
||||
onSelectDimension: (dimension?: DrillDownDimensionType) => void;
|
||||
onApplyAuth?: (domain: string) => void;
|
||||
onApplyAuth?: (model: string) => void;
|
||||
};
|
||||
|
||||
const BarChart: React.FC<Props> = ({
|
||||
@@ -152,7 +152,7 @@ const BarChart: React.FC<Props> = ({
|
||||
if (metricColumn && !metricColumn?.authorized) {
|
||||
return (
|
||||
<NoPermissionChart
|
||||
domain={entityInfo?.domainInfo.name || ''}
|
||||
model={entityInfo?.modelInfo.name || ''}
|
||||
chartType="barChart"
|
||||
onApplyAuth={onApplyAuth}
|
||||
/>
|
||||
@@ -193,11 +193,9 @@ const BarChart: React.FC<Props> = ({
|
||||
<Spin spinning={loading}>
|
||||
<div className={`${prefixCls}-chart`} ref={chartRef} />
|
||||
</Spin>
|
||||
{(queryMode === 'METRIC_DOMAIN' ||
|
||||
queryMode === 'METRIC_FILTER' ||
|
||||
queryMode === 'METRIC_GROUPBY') && (
|
||||
{queryMode.includes('METRIC') && (
|
||||
<DrillDownDimensions
|
||||
domainId={chatContext.domainId}
|
||||
modelId={chatContext.modelId}
|
||||
drillDownDimension={drillDownDimension}
|
||||
dimensionFilters={chatContext.dimensionFilters}
|
||||
onSelectDimension={onSelectDimension}
|
||||
|
||||
@@ -26,7 +26,7 @@ const Message: React.FC<Props> = ({
|
||||
}) => {
|
||||
const prefixCls = `${PREFIX_CLS}-message`;
|
||||
|
||||
const { domainName, dateInfo, dimensionFilters } = chatContext || {};
|
||||
const { modelName, dateInfo, dimensionFilters } = chatContext || {};
|
||||
const { startDate, endDate } = dateInfo || {};
|
||||
|
||||
const entityInfoList =
|
||||
@@ -67,7 +67,7 @@ const Message: React.FC<Props> = ({
|
||||
<div className={`${prefixCls}-main-entity-info`}>
|
||||
<div className={`${prefixCls}-info-item`}>
|
||||
<div className={`${prefixCls}-info-name`}>主题域:</div>
|
||||
<div className={`${prefixCls}-info-value`}>{domainName}</div>
|
||||
<div className={`${prefixCls}-info-value`}>{modelName}</div>
|
||||
</div>
|
||||
<div className={`${prefixCls}-info-item`}>
|
||||
<div className={`${prefixCls}-info-name`}>时间:</div>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
&-domain-name {
|
||||
&-model-name {
|
||||
color: var(--text-color);
|
||||
margin-left: 4px;
|
||||
font-weight: 500;
|
||||
|
||||
@@ -13,7 +13,7 @@ type Props = {
|
||||
drillDownDimension?: DrillDownDimensionType;
|
||||
loading: boolean;
|
||||
onSelectDimension: (dimension?: DrillDownDimensionType) => void;
|
||||
onApplyAuth?: (domain: string) => void;
|
||||
onApplyAuth?: (model: string) => void;
|
||||
};
|
||||
|
||||
const MetricCard: React.FC<Props> = ({
|
||||
@@ -64,7 +64,7 @@ const MetricCard: React.FC<Props> = ({
|
||||
<div className={indicatorClass}>
|
||||
<div className={`${prefixCls}-date-range`}>{startDate}</div>
|
||||
{indicatorColumn && !indicatorColumn?.authorized ? (
|
||||
<ApplyAuth domain={entityInfo?.domainInfo.name || ''} onApplyAuth={onApplyAuth} />
|
||||
<ApplyAuth model={entityInfo?.modelInfo.name || ''} onApplyAuth={onApplyAuth} />
|
||||
) : (
|
||||
<div className={`${prefixCls}-indicator-value`}>
|
||||
{formatMetric(queryResults?.[0]?.[indicatorColumnName]) || '-'}
|
||||
@@ -79,10 +79,10 @@ const MetricCard: React.FC<Props> = ({
|
||||
)}
|
||||
</div>
|
||||
</Spin>
|
||||
{(queryMode === 'METRIC_DOMAIN' || queryMode === 'METRIC_FILTER') && (
|
||||
{queryMode.includes('METRIC') && (
|
||||
<div className={`${prefixCls}-drill-down-dimensions`}>
|
||||
<DrillDownDimensions
|
||||
domainId={chatContext.domainId}
|
||||
modelId={chatContext.modelId}
|
||||
dimensionFilters={chatContext.dimensionFilters}
|
||||
drillDownDimension={drillDownDimension}
|
||||
onSelectDimension={onSelectDimension}
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
|
||||
&-drill-down-dimensions {
|
||||
position: absolute;
|
||||
bottom: -44px;
|
||||
left: -16;
|
||||
bottom: -38px;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
@@ -14,17 +14,17 @@ import { ColumnType } from '../../../common/type';
|
||||
import NoPermissionChart from '../NoPermissionChart';
|
||||
|
||||
type Props = {
|
||||
domain?: string;
|
||||
model?: string;
|
||||
dateColumnName: string;
|
||||
categoryColumnName: string;
|
||||
metricField: ColumnType;
|
||||
resultList: any[];
|
||||
triggerResize?: boolean;
|
||||
onApplyAuth?: (domain: string) => void;
|
||||
onApplyAuth?: (model: string) => void;
|
||||
};
|
||||
|
||||
const MetricTrendChart: React.FC<Props> = ({
|
||||
domain,
|
||||
model,
|
||||
dateColumnName,
|
||||
categoryColumnName,
|
||||
metricField,
|
||||
@@ -204,7 +204,7 @@ const MetricTrendChart: React.FC<Props> = ({
|
||||
return (
|
||||
<div>
|
||||
{!metricField.authorized ? (
|
||||
<NoPermissionChart domain={domain || ''} onApplyAuth={onApplyAuth} />
|
||||
<NoPermissionChart model={model || ''} onApplyAuth={onApplyAuth} />
|
||||
) : (
|
||||
<div className={`${prefixCls}-flow-trend-chart`} ref={chartRef} />
|
||||
)}
|
||||
|
||||
@@ -15,7 +15,7 @@ type Props = {
|
||||
data: MsgDataType;
|
||||
chartIndex: number;
|
||||
triggerResize?: boolean;
|
||||
onApplyAuth?: (domain: string) => void;
|
||||
onApplyAuth?: (model: string) => void;
|
||||
};
|
||||
|
||||
const MetricTrend: React.FC<Props> = ({ data, chartIndex, triggerResize, onApplyAuth }) => {
|
||||
@@ -36,6 +36,7 @@ const MetricTrend: React.FC<Props> = ({ data, chartIndex, triggerResize, onApply
|
||||
const [currentDateOption, setCurrentDateOption] = useState<number>(initialDateOption);
|
||||
const [dimensions, setDimensions] = useState<FieldType[]>(chatContext?.dimensions);
|
||||
const [drillDownDimension, setDrillDownDimension] = useState<DrillDownDimensionType>();
|
||||
const [aggregateInfoValue, setAggregateInfoValue] = useState<any>(aggregateInfo);
|
||||
const [dateModeValue, setDateModeValue] = useState(dateMode);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
@@ -72,6 +73,7 @@ const MetricTrend: React.FC<Props> = ({ data, chartIndex, triggerResize, onApply
|
||||
if (data.code === 200) {
|
||||
setColumns(data.data?.queryColumns || []);
|
||||
setDataSource(data.data?.queryResults || []);
|
||||
setAggregateInfoValue(data.data?.aggregateInfo);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -172,7 +174,9 @@ const MetricTrend: React.FC<Props> = ({ data, chartIndex, triggerResize, onApply
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{aggregateInfo?.metricInfos?.length > 0 && <MetricInfo aggregateInfo={aggregateInfo} />}
|
||||
{aggregateInfoValue?.metricInfos?.length > 0 && (
|
||||
<MetricInfo aggregateInfo={aggregateInfoValue} />
|
||||
)}
|
||||
<div className={`${prefixCls}-date-options`}>
|
||||
{dateOptions.map((dateOption: { label: string; value: number }, index: number) => {
|
||||
const dateOptionClass = classNames(`${prefixCls}-date-option`, {
|
||||
@@ -205,7 +209,7 @@ const MetricTrend: React.FC<Props> = ({ data, chartIndex, triggerResize, onApply
|
||||
<Table data={{ ...data, queryResults: dataSource }} onApplyAuth={onApplyAuth} />
|
||||
) : (
|
||||
<MetricTrendChart
|
||||
domain={entityInfo?.domainInfo.name}
|
||||
model={entityInfo?.modelInfo.name}
|
||||
dateColumnName={dateColumnName}
|
||||
categoryColumnName={categoryColumnName}
|
||||
metricField={currentMetricField}
|
||||
@@ -215,11 +219,9 @@ const MetricTrend: React.FC<Props> = ({ data, chartIndex, triggerResize, onApply
|
||||
/>
|
||||
)}
|
||||
</Spin>
|
||||
{(queryMode === 'METRIC_DOMAIN' ||
|
||||
queryMode === 'METRIC_FILTER' ||
|
||||
queryMode === 'METRIC_GROUPBY') && (
|
||||
{queryMode.includes('METRIC') && (
|
||||
<DrillDownDimensions
|
||||
domainId={chatContext.domainId}
|
||||
modelId={chatContext.modelId}
|
||||
drillDownDimension={drillDownDimension}
|
||||
dimensionFilters={chatContext.dimensionFilters}
|
||||
onSelectDimension={onSelectDimension}
|
||||
|
||||
@@ -3,12 +3,12 @@ import { CLS_PREFIX } from '../../../common/constants';
|
||||
import ApplyAuth from '../ApplyAuth';
|
||||
|
||||
type Props = {
|
||||
domain: string;
|
||||
model: string;
|
||||
chartType?: string;
|
||||
onApplyAuth?: (domain: string) => void;
|
||||
onApplyAuth?: (model: string) => void;
|
||||
};
|
||||
|
||||
const NoPermissionChart: React.FC<Props> = ({ domain, chartType, onApplyAuth }) => {
|
||||
const NoPermissionChart: React.FC<Props> = ({ model, chartType, onApplyAuth }) => {
|
||||
const prefixCls = `${CLS_PREFIX}-no-permission-chart`;
|
||||
|
||||
const chartHolderClass = classNames(`${prefixCls}-holder`, {
|
||||
@@ -19,7 +19,7 @@ const NoPermissionChart: React.FC<Props> = ({ domain, chartType, onApplyAuth })
|
||||
<div className={prefixCls}>
|
||||
<div className={chartHolderClass} />
|
||||
<div className={`${prefixCls}-no-permission`}>
|
||||
<ApplyAuth domain={domain} onApplyAuth={onApplyAuth} />
|
||||
<ApplyAuth model={model} onApplyAuth={onApplyAuth} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -8,7 +8,7 @@ import { SizeType } from 'antd/es/config-provider/SizeContext';
|
||||
type Props = {
|
||||
data: MsgDataType;
|
||||
size?: SizeType;
|
||||
onApplyAuth?: (domain: string) => void;
|
||||
onApplyAuth?: (model: string) => void;
|
||||
};
|
||||
|
||||
const Table: React.FC<Props> = ({ data, size, onApplyAuth }) => {
|
||||
@@ -24,9 +24,7 @@ const Table: React.FC<Props> = ({ data, size, onApplyAuth }) => {
|
||||
title: name || nameEn,
|
||||
render: (value: string | number) => {
|
||||
if (!authorized) {
|
||||
return (
|
||||
<ApplyAuth domain={entityInfo?.domainInfo.name || ''} onApplyAuth={onApplyAuth} />
|
||||
);
|
||||
return <ApplyAuth model={entityInfo?.modelInfo.name || ''} onApplyAuth={onApplyAuth} />;
|
||||
}
|
||||
if (dataFormatType === 'percent') {
|
||||
return (
|
||||
@@ -71,7 +69,7 @@ const Table: React.FC<Props> = ({ data, size, onApplyAuth }) => {
|
||||
columns={tableColumns}
|
||||
dataSource={queryResults}
|
||||
style={{ width: '100%' }}
|
||||
scroll={{ x: 'max-content' }}
|
||||
// scroll={{ x: 'max-content' }}
|
||||
rowClassName={getRowClassName}
|
||||
size={size}
|
||||
/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
@table-prefix-cls: ~'@{supersonic-chat-prefix}-table';
|
||||
|
||||
.@{table-prefix-cls} {
|
||||
margin-top: 20px;
|
||||
margin-top: 16px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
&-photo {
|
||||
|
||||
@@ -35,10 +35,15 @@ const ChatMsg: React.FC<Props> = ({ question, data, chartIndex, isMobileMode, tr
|
||||
const metricFields = columns.filter(item => item.showType === 'NUMBER');
|
||||
|
||||
const isMetricCard =
|
||||
(queryMode === 'METRIC_DOMAIN' || queryMode === 'METRIC_FILTER') &&
|
||||
queryMode.includes('METRIC') &&
|
||||
(singleData || chatContext?.dateInfo?.startDate === chatContext?.dateInfo?.endDate);
|
||||
|
||||
const isText = columns.length === 1 && columns[0].showType === 'CATEGORY' && singleData;
|
||||
const isText =
|
||||
columns.length === 1 &&
|
||||
columns[0].showType === 'CATEGORY' &&
|
||||
!queryMode.includes('METRIC') &&
|
||||
!queryMode.includes('ENTITY') &&
|
||||
singleData;
|
||||
|
||||
const onLoadData = async (value: any) => {
|
||||
setLoading(true);
|
||||
|
||||
@@ -7,7 +7,7 @@ import { DownOutlined } from '@ant-design/icons';
|
||||
import classNames from 'classnames';
|
||||
|
||||
type Props = {
|
||||
domainId: number;
|
||||
modelId: number;
|
||||
drillDownDimension?: DrillDownDimensionType;
|
||||
isMetricCard?: boolean;
|
||||
dimensionFilters?: FilterItemType[];
|
||||
@@ -17,7 +17,7 @@ type Props = {
|
||||
const MAX_DIMENSION_COUNT = 20;
|
||||
|
||||
const DrillDownDimensions: React.FC<Props> = ({
|
||||
domainId,
|
||||
modelId,
|
||||
drillDownDimension,
|
||||
isMetricCard,
|
||||
dimensionFilters,
|
||||
@@ -30,7 +30,7 @@ const DrillDownDimensions: React.FC<Props> = ({
|
||||
const prefixCls = `${CLS_PREFIX}-drill-down-dimensions`;
|
||||
|
||||
const initData = async () => {
|
||||
const res = await queryDrillDownDimensions(domainId);
|
||||
const res = await queryDrillDownDimensions(modelId);
|
||||
setDimensions(
|
||||
res.data.data.dimensions
|
||||
.filter(dimension => !dimensionFilters?.some(filter => filter.name === dimension.name))
|
||||
|
||||
@@ -10,16 +10,16 @@ import classNames from 'classnames';
|
||||
|
||||
type Props = {
|
||||
entityId: string | number;
|
||||
domainId: number;
|
||||
domainName: string;
|
||||
modelId: number;
|
||||
modelName: string;
|
||||
isMobileMode?: boolean;
|
||||
onSelect: (option: string) => void;
|
||||
};
|
||||
|
||||
const RecommendOptions: React.FC<Props> = ({
|
||||
entityId,
|
||||
domainId,
|
||||
domainName,
|
||||
modelId,
|
||||
modelName,
|
||||
isMobileMode,
|
||||
onSelect,
|
||||
}) => {
|
||||
@@ -30,7 +30,7 @@ const RecommendOptions: React.FC<Props> = ({
|
||||
|
||||
const initData = async () => {
|
||||
setLoading(true);
|
||||
const res = await queryEntities(entityId, domainId);
|
||||
const res = await queryEntities(entityId, modelId);
|
||||
setLoading(false);
|
||||
setData(res.data.data);
|
||||
};
|
||||
@@ -51,7 +51,7 @@ const RecommendOptions: React.FC<Props> = ({
|
||||
<div className={`${prefixCls}-item-name-column`}>
|
||||
<Avatar
|
||||
shape="square"
|
||||
icon={<IconFont type={domainName === '艺人库' ? 'icon-geshou' : 'icon-zhuanji'} />}
|
||||
icon={<IconFont type={modelName === '艺人库' ? 'icon-geshou' : 'icon-zhuanji'} />}
|
||||
src={record.url}
|
||||
/>
|
||||
<div className={`${prefixCls}-entity-name`}>
|
||||
@@ -64,7 +64,7 @@ const RecommendOptions: React.FC<Props> = ({
|
||||
},
|
||||
};
|
||||
|
||||
const playCntColumnIdex = domainName.includes('歌曲')
|
||||
const playCntColumnIdex = modelName.includes('歌曲')
|
||||
? 'tme3platAvgLogYyPlayCnt'
|
||||
: 'tme3platJsPlayCnt';
|
||||
|
||||
@@ -72,7 +72,7 @@ const RecommendOptions: React.FC<Props> = ({
|
||||
? [basicColumn]
|
||||
: [
|
||||
basicColumn,
|
||||
domainName.includes('艺人')
|
||||
modelName.includes('艺人')
|
||||
? {
|
||||
dataIndex: 'onlineSongCnt',
|
||||
key: 'onlineSongCnt',
|
||||
@@ -95,7 +95,7 @@ const RecommendOptions: React.FC<Props> = ({
|
||||
dataIndex: playCntColumnIdex,
|
||||
key: playCntColumnIdex,
|
||||
align: 'center',
|
||||
title: domainName.includes('歌曲') ? '近7天日均运营播放量' : '昨日结算播放量',
|
||||
title: modelName.includes('歌曲') ? '近7天日均运营播放量' : '昨日结算播放量',
|
||||
render: (value: string) => {
|
||||
return value ? getFormattedValue(+value) : '-';
|
||||
},
|
||||
|
||||
@@ -26,21 +26,22 @@ const Tools: React.FC<Props> = ({
|
||||
onChangeChart,
|
||||
}) => {
|
||||
const [recommendOptionsOpen, setRecommendOptionsOpen] = useState(false);
|
||||
const { queryColumns, queryResults, queryId, chatContext, queryMode } = data || {};
|
||||
const { queryColumns, queryResults, queryId, chatContext, queryMode, entityInfo } = data || {};
|
||||
const [score, setScore] = useState(scoreValue || 0);
|
||||
|
||||
const prefixCls = `${CLS_PREFIX}-tools`;
|
||||
|
||||
const singleData = queryResults.length === 1;
|
||||
const isMetricCard =
|
||||
queryMode.includes('METRIC') &&
|
||||
(singleData || chatContext?.dateInfo?.startDate === chatContext?.dateInfo?.endDate);
|
||||
|
||||
const noDashboard =
|
||||
(queryColumns?.length === 1 &&
|
||||
queryColumns[0].showType === 'CATEGORY' &&
|
||||
queryResults?.length === 1) ||
|
||||
(!queryMode.includes('METRIC') && !queryMode.includes('ENTITY'));
|
||||
|
||||
console.log(
|
||||
'chatContext?.properties?.CONTEXT?.plugin?.name',
|
||||
chatContext?.properties?.CONTEXT?.plugin?.name
|
||||
);
|
||||
(!queryMode.includes('METRIC') && !queryMode.includes('ENTITY')) ||
|
||||
isMetricCard;
|
||||
|
||||
const changeChart = () => {
|
||||
onChangeChart();
|
||||
@@ -74,13 +75,13 @@ const Tools: React.FC<Props> = ({
|
||||
|
||||
return (
|
||||
<div className={prefixCls}>
|
||||
{/* {isLastMessage && chatContext?.domainId && entityInfo?.entityId && (
|
||||
{/* {isLastMessage && chatContext?.modelId && entityInfo?.entityId && (
|
||||
<Popover
|
||||
content={
|
||||
<RecommendOptions
|
||||
entityId={entityInfo.entityId}
|
||||
domainId={chatContext.domainId}
|
||||
domainName={chatContext.domainName}
|
||||
modelId={chatContext.modelId}
|
||||
modelName={chatContext.modelName}
|
||||
isMobileMode={isMobileMode}
|
||||
onSelect={switchEntity}
|
||||
/>
|
||||
@@ -105,7 +106,7 @@ const Tools: React.FC<Props> = ({
|
||||
加入看板
|
||||
</Button>
|
||||
)}
|
||||
{isLastMessage && (
|
||||
{isLastMessage && !isMetricCard && (
|
||||
<div className={`${prefixCls}-feedback`}>
|
||||
<div>这个回答正确吗?</div>
|
||||
<LikeOutlined className={likeClass} onClick={like} />
|
||||
|
||||
@@ -56,7 +56,6 @@ const Chat = () => {
|
||||
msg={msg}
|
||||
// msgData={data}
|
||||
onMsgDataLoaded={onMsgDataLoaded}
|
||||
domainId={37}
|
||||
isLastMessage
|
||||
isMobileMode
|
||||
triggerResize={triggerResize}
|
||||
|
||||
@@ -19,7 +19,7 @@ export { default as ChatItem } from './components/ChatItem';
|
||||
export type {
|
||||
SearchRecommendItem,
|
||||
FieldType,
|
||||
DomainInfoType,
|
||||
ModelInfoType,
|
||||
EntityInfoType,
|
||||
DateInfoType,
|
||||
ChatContextType,
|
||||
|
||||
@@ -6,30 +6,30 @@ const DEFAULT_CHAT_ID = 0;
|
||||
|
||||
const prefix = '/api';
|
||||
|
||||
export function searchRecommend(queryText: string, chatId?: number, domainId?: number) {
|
||||
export function searchRecommend(queryText: string, chatId?: number, modelId?: number) {
|
||||
return axios.post<Result<SearchRecommendItem[]>>(`${prefix}/chat/query/search`, {
|
||||
queryText,
|
||||
chatId: chatId || DEFAULT_CHAT_ID,
|
||||
domainId,
|
||||
modelId,
|
||||
});
|
||||
}
|
||||
|
||||
export function chatQuery(queryText: string, chatId?: number, domainId?: number, filters?: any[]) {
|
||||
export function chatQuery(queryText: string, chatId?: number, modelId?: number, filters?: any[]) {
|
||||
return axios.post<Result<MsgDataType>>(`${prefix}/chat/query/query`, {
|
||||
queryText,
|
||||
chatId: chatId || DEFAULT_CHAT_ID,
|
||||
domainId,
|
||||
modelId,
|
||||
queryFilters: filters ? {
|
||||
filters
|
||||
} : undefined,
|
||||
});
|
||||
}
|
||||
|
||||
export function chatParse(queryText: string, chatId?: number, domainId?: number, filters?: any[]) {
|
||||
export function chatParse(queryText: string, chatId?: number, modelId?: number, filters?: any[]) {
|
||||
return axios.post<Result<ParseDataType>>(`${prefix}/chat/query/parse`, {
|
||||
queryText,
|
||||
chatId: chatId || DEFAULT_CHAT_ID,
|
||||
domainId,
|
||||
modelId,
|
||||
queryFilters: filters ? {
|
||||
filters
|
||||
} : undefined,
|
||||
@@ -44,10 +44,10 @@ export function chatExecute(queryText: string, chatId: number, parseInfo: ChatC
|
||||
});
|
||||
}
|
||||
|
||||
export function switchEntity(entityId: string, domainId?: number, chatId?: number) {
|
||||
export function switchEntity(entityId: string, modelId?: number, chatId?: number) {
|
||||
return axios.post<Result<any>>(`${prefix}/chat/query/switchQuery`, {
|
||||
queryText: entityId,
|
||||
domainId,
|
||||
modelId,
|
||||
chatId: chatId || DEFAULT_CHAT_ID,
|
||||
});
|
||||
}
|
||||
@@ -63,8 +63,8 @@ export function queryContext(queryText: string, chatId?: number) {
|
||||
});
|
||||
}
|
||||
|
||||
export function querySuggestionInfo(domainId: number) {
|
||||
return axios.get<Result<any>>(`${prefix}/chat/recommend/${domainId}`);
|
||||
export function querySuggestionInfo(modelId: number) {
|
||||
return axios.get<Result<any>>(`${prefix}/chat/recommend/${modelId}`);
|
||||
}
|
||||
|
||||
export function getHistoryMsg(current: number, chatId: number = DEFAULT_CHAT_ID, pageSize: number = 10) {
|
||||
@@ -98,10 +98,10 @@ export function getAllConversations() {
|
||||
return axios.get<Result<any>>(`${prefix}/chat/manage/getAll`);
|
||||
}
|
||||
|
||||
export function queryEntities(entityId: string | number, domainId: number) {
|
||||
export function queryEntities(entityId: string | number, modelId: number) {
|
||||
return axios.post<Result<any>>(`${prefix}/chat/query/choice`, {
|
||||
entityId,
|
||||
domainId,
|
||||
modelId,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -109,6 +109,6 @@ export function updateQAFeedback(questionId: number, score: number) {
|
||||
return axios.post<Result<any>>(`${prefix}/chat/manage/updateQAFeedback?id=${questionId}&score=${score}&feedback=`);
|
||||
}
|
||||
|
||||
export function queryDrillDownDimensions(domainId: number) {
|
||||
return axios.get<Result<{ dimensions: DrillDownDimensionType[] }>>(`${prefix}/chat/recommend/metric/${domainId}`);
|
||||
export function queryDrillDownDimensions(modelId: number) {
|
||||
return axios.get<Result<{ dimensions: DrillDownDimensionType[] }>>(`${prefix}/chat/recommend/metric/${modelId}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user