mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-05 05:29:26 +08:00
feat(data-vi): add extended API for field interface configuration (#6742)
* feat(data-vi): add extend api * feat(data-vi): add extend API for field interface configuration
This commit is contained in:
parent
b923d89fa0
commit
757765228f
@ -1,81 +0,0 @@
|
||||
/**
|
||||
* This file is part of the NocoBase (R) project.
|
||||
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||
* Authors: NocoBase Team.
|
||||
*
|
||||
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import { processData } from '../utils';
|
||||
|
||||
describe('utils', () => {
|
||||
describe('process data', () => {
|
||||
it('should process select field', () => {
|
||||
expect(
|
||||
processData(
|
||||
[
|
||||
{
|
||||
name: 'tag',
|
||||
type: 'bigInt',
|
||||
interface: 'select',
|
||||
uiSchema: {
|
||||
type: 'string',
|
||||
enum: [
|
||||
{
|
||||
value: '1',
|
||||
label: 'Yes',
|
||||
},
|
||||
{
|
||||
value: '2',
|
||||
label: 'No',
|
||||
},
|
||||
],
|
||||
},
|
||||
label: 'Tag',
|
||||
value: 'tag',
|
||||
key: 'tag',
|
||||
},
|
||||
],
|
||||
[{ tag: 1 }],
|
||||
{},
|
||||
),
|
||||
).toEqual([{ tag: 'Yes' }]);
|
||||
});
|
||||
it('should not process when aggregating', () => {
|
||||
expect(
|
||||
processData(
|
||||
[
|
||||
{
|
||||
name: 'tag',
|
||||
type: 'bigInt',
|
||||
interface: 'select',
|
||||
uiSchema: {
|
||||
type: 'string',
|
||||
enum: [
|
||||
{
|
||||
value: '1',
|
||||
label: 'Yes',
|
||||
},
|
||||
{
|
||||
value: '2',
|
||||
label: 'No',
|
||||
},
|
||||
],
|
||||
},
|
||||
label: 'Tag',
|
||||
value: 'tag',
|
||||
key: 'tag',
|
||||
query: {
|
||||
field: 'tag',
|
||||
aggregation: 'count',
|
||||
},
|
||||
},
|
||||
],
|
||||
[{ tag: 1 }],
|
||||
{},
|
||||
),
|
||||
).toEqual([{ tag: 1 }]);
|
||||
});
|
||||
});
|
||||
});
|
@ -14,6 +14,7 @@ import {
|
||||
DEFAULT_DATA_SOURCE_KEY,
|
||||
useACLRoleContext,
|
||||
useDataSourceManager,
|
||||
usePlugin,
|
||||
} from '@nocobase/client';
|
||||
import { useContext, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@ -21,7 +22,8 @@ import { ChartConfigContext } from '../configure';
|
||||
import formatters from '../configure/formatters';
|
||||
import { useChartsTranslation } from '../locale';
|
||||
import { ChartRendererContext } from '../renderer';
|
||||
import { getField, getSelectedFields, parseField, processData } from '../utils';
|
||||
import { getField, getSelectedFields, parseField } from '../utils';
|
||||
import PluginDataVisualiztionClient from '..';
|
||||
|
||||
export type FieldOption = {
|
||||
value: string;
|
||||
@ -226,12 +228,36 @@ export const useOrderReaction = (defaultOptions: any[], fields: FieldOption[]) =
|
||||
};
|
||||
|
||||
export const useData = (data?: any[], dataSource?: string, collection?: string) => {
|
||||
const { t } = useChartsTranslation();
|
||||
const { service, query } = useContext(ChartRendererContext);
|
||||
const plugin = usePlugin(PluginDataVisualiztionClient);
|
||||
const fields = useFieldsWithAssociation(dataSource, collection);
|
||||
const form = useForm();
|
||||
const selectedFields = getSelectedFields(fields, form?.values?.query || query);
|
||||
return processData(selectedFields, service?.data || data || [], { t });
|
||||
const selectedFields = getSelectedFields(fields, form?.values?.query || query) as (FieldOption & { query?: any })[];
|
||||
const fieldInterfaceConfigs = plugin.fieldInterfaceConfigs;
|
||||
const formatters = {};
|
||||
for (const field of selectedFields) {
|
||||
if (field?.query?.aggregation) {
|
||||
continue;
|
||||
}
|
||||
const config = fieldInterfaceConfigs[field.interface];
|
||||
if (!config) {
|
||||
continue;
|
||||
}
|
||||
const { valueFormatter } = config;
|
||||
formatters[field.value] = (value: any) => valueFormatter(field, value);
|
||||
}
|
||||
return (service?.data || data || []).map((record: any) => {
|
||||
const processed = {};
|
||||
Object.entries(record).forEach(([key, value]) => {
|
||||
const formatter = formatters[key];
|
||||
if (!formatter) {
|
||||
processed[key] = value;
|
||||
return;
|
||||
}
|
||||
processed[key] = formatter(value);
|
||||
});
|
||||
return processed;
|
||||
});
|
||||
};
|
||||
|
||||
export const useCollectionFieldsOptions = (dataSource: string, collectionName: string, maxDepth = 2, excludes = []) => {
|
||||
|
@ -41,10 +41,42 @@ import { useChartRefreshActionProps } from './initializers/RefreshAction';
|
||||
import { useChartBlockRefreshActionProps } from './initializers/BlockRefreshAction';
|
||||
import { ChartRendererToolbar, ChartFilterBlockToolbar, ChartFilterItemToolbar } from './toolbar';
|
||||
import { ChartCardItem } from './block/CardItem';
|
||||
import { Schema } from '@formily/react';
|
||||
|
||||
type fieldInterfaceConfig = {
|
||||
valueFormatter: (field: any, value: any) => any;
|
||||
};
|
||||
|
||||
const valueFormatter = (field: any, value: any) => {
|
||||
const options = field.uiSchema?.enum;
|
||||
const parseEnumValues = (options: { label: string; value: string }[], value: any) => {
|
||||
if (Array.isArray(value)) {
|
||||
return value.map((v) => parseEnumValues(options, v));
|
||||
}
|
||||
const option = options.find((option) => option.value === (value?.toString?.() || value));
|
||||
return Schema.compile(option?.label || value, { t: lang });
|
||||
};
|
||||
if (!options || !Array.isArray(options)) {
|
||||
return value;
|
||||
}
|
||||
return parseEnumValues(options, value);
|
||||
};
|
||||
|
||||
class PluginDataVisualiztionClient extends Plugin {
|
||||
public charts: ChartGroup = new ChartGroup();
|
||||
|
||||
fieldInterfaceConfigs: {
|
||||
[fieldInterface: string]: fieldInterfaceConfig;
|
||||
} = {
|
||||
select: { valueFormatter },
|
||||
multipleSelect: { valueFormatter },
|
||||
radioGroup: { valueFormatter },
|
||||
};
|
||||
|
||||
registerFieldInterfaceConfig(key: string, config: fieldInterfaceConfig) {
|
||||
this.fieldInterfaceConfigs[key] = config;
|
||||
}
|
||||
|
||||
async load() {
|
||||
this.charts.addGroup('antd', { title: 'Ant Design', charts: antd });
|
||||
this.charts.addGroup('ant-design-charts', { title: 'Ant Design Charts', charts: g2plot });
|
||||
|
@ -106,40 +106,6 @@ export const getSelectedFields = (fields: FieldOption[], query: QueryProps) => {
|
||||
return selectedFields;
|
||||
};
|
||||
|
||||
export const processData = (selectedFields: (FieldOption & { query?: any })[], data: any[], scope: any) => {
|
||||
const parseEnum = (field: FieldOption, value: any) => {
|
||||
const options = field.uiSchema?.enum as { value: string; label: string }[];
|
||||
if (!options || !Array.isArray(options)) {
|
||||
return value;
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
return value.map((v) => parseEnum(field, v));
|
||||
}
|
||||
const option = options.find((option) => option.value === (value?.toString?.() || value));
|
||||
return Schema.compile(option?.label || value, scope);
|
||||
};
|
||||
return data.map((record) => {
|
||||
const processed = {};
|
||||
Object.entries(record).forEach(([key, value]) => {
|
||||
const field = selectedFields.find((field) => field.value === key && !field?.query?.aggregation);
|
||||
if (!field) {
|
||||
processed[key] = value;
|
||||
return;
|
||||
}
|
||||
switch (field.interface) {
|
||||
case 'select':
|
||||
case 'radioGroup':
|
||||
case 'multipleSelect':
|
||||
processed[key] = parseEnum(field, value);
|
||||
break;
|
||||
default:
|
||||
processed[key] = value;
|
||||
}
|
||||
});
|
||||
return processed;
|
||||
});
|
||||
};
|
||||
|
||||
export const removeUnparsableFilter = (filter: any) => {
|
||||
if (typeof filter === 'object' && filter !== null) {
|
||||
if (Array.isArray(filter)) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user