mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-05 13:39:24 +08:00
feat(data-vi): optimize style settings for chart blocks (#4940)
* feat(data-vi): adapt styles to mobile client * fix: style * chore: update * fix: bug * fix: bug
This commit is contained in:
parent
fe2a679132
commit
de1994521a
@ -14,6 +14,7 @@ import { ChartDataProvider } from './ChartDataProvider';
|
|||||||
import { ChartRenderer, ChartRendererProvider } from '../renderer';
|
import { ChartRenderer, ChartRendererProvider } from '../renderer';
|
||||||
import { ChartFilterBlockProvider, ChartFilterBlockDesigner } from '../filter';
|
import { ChartFilterBlockProvider, ChartFilterBlockDesigner } from '../filter';
|
||||||
import { ChartFilterProvider } from '../filter/FilterProvider';
|
import { ChartFilterProvider } from '../filter/FilterProvider';
|
||||||
|
import { css } from '@emotion/css';
|
||||||
|
|
||||||
export const ChartV2Block: React.FC = (props) => {
|
export const ChartV2Block: React.FC = (props) => {
|
||||||
const [initialVisible, setInitialVisible] = useState(false);
|
const [initialVisible, setInitialVisible] = useState(false);
|
||||||
@ -25,11 +26,24 @@ export const ChartV2Block: React.FC = (props) => {
|
|||||||
<SchemaComponentOptions
|
<SchemaComponentOptions
|
||||||
components={{ ChartRenderer, ChartRendererProvider, ChartFilterBlockProvider, ChartFilterBlockDesigner }}
|
components={{ ChartRenderer, ChartRendererProvider, ChartFilterBlockProvider, ChartFilterBlockDesigner }}
|
||||||
>
|
>
|
||||||
<ChartDataProvider>
|
<div
|
||||||
<ChartFilterProvider>
|
className={css`
|
||||||
<ChartConfigProvider>{props.children}</ChartConfigProvider>
|
.ant-nb-card-item {
|
||||||
</ChartFilterProvider>
|
.ant-card {
|
||||||
</ChartDataProvider>
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.nb-grid-warp > button:last-child {
|
||||||
|
margin-bottom: 24px !important;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<ChartDataProvider>
|
||||||
|
<ChartFilterProvider>
|
||||||
|
<ChartConfigProvider>{props.children}</ChartConfigProvider>
|
||||||
|
</ChartFilterProvider>
|
||||||
|
</ChartDataProvider>
|
||||||
|
</div>
|
||||||
</SchemaComponentOptions>
|
</SchemaComponentOptions>
|
||||||
</SchemaInitializerContext.Provider>
|
</SchemaInitializerContext.Provider>
|
||||||
);
|
);
|
||||||
|
@ -12,15 +12,65 @@ import {
|
|||||||
SchemaSettingsBlockTitleItem,
|
SchemaSettingsBlockTitleItem,
|
||||||
SchemaSettingsDivider,
|
SchemaSettingsDivider,
|
||||||
SchemaSettingsRemove,
|
SchemaSettingsRemove,
|
||||||
|
SchemaSettingsSelectItem,
|
||||||
|
SchemaSettingsSwitchItem,
|
||||||
|
useDesignable,
|
||||||
|
useToken,
|
||||||
} from '@nocobase/client';
|
} from '@nocobase/client';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useChartsTranslation } from '../locale';
|
import { useChartsTranslation } from '../locale';
|
||||||
|
import { useField, useFieldSchema } from '@formily/react';
|
||||||
|
|
||||||
export const ChartV2BlockDesigner: React.FC = () => {
|
export const ChartV2BlockDesigner: React.FC = () => {
|
||||||
const { t } = useChartsTranslation();
|
const { t } = useChartsTranslation();
|
||||||
|
const field = useField();
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const { dn } = useDesignable();
|
||||||
|
const { token } = useToken();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GeneralSchemaDesigner title={t('Charts')} showDataSource={false}>
|
<GeneralSchemaDesigner title={t('Charts')} showDataSource={false}>
|
||||||
<SchemaSettingsBlockTitleItem />
|
<SchemaSettingsBlockTitleItem />
|
||||||
|
<SchemaSettingsSwitchItem
|
||||||
|
title={t('Show background')}
|
||||||
|
checked={field.componentProps.style?.background !== 'none'}
|
||||||
|
onChange={(v) => {
|
||||||
|
const style = {
|
||||||
|
...field.componentProps.style,
|
||||||
|
background: v ? token.colorBgContainer : 'none',
|
||||||
|
boxShadow: v ? token.boxShadowTertiary : 'none',
|
||||||
|
};
|
||||||
|
field.componentProps.style = style;
|
||||||
|
field.componentProps.bordered = v;
|
||||||
|
fieldSchema['x-component-props'] = field.componentProps;
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema: {
|
||||||
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
|
'x-component-props': field.componentProps,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
dn.refresh();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<SchemaSettingsSwitchItem
|
||||||
|
title={t('Show padding')}
|
||||||
|
checked={field.componentProps.bodyStyle?.padding !== '5px 0 0'}
|
||||||
|
onChange={(v) => {
|
||||||
|
const style = {
|
||||||
|
...field.componentProps.bodyStyle,
|
||||||
|
padding: v ? `${token.paddingLG}px ${token.paddingLG}px 0` : '5px 0 0',
|
||||||
|
};
|
||||||
|
field.componentProps.bodyStyle = style;
|
||||||
|
fieldSchema['x-component-props'] = field.componentProps;
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema: {
|
||||||
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
|
'x-component-props': field.componentProps,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
dn.refresh();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
<SchemaSettingsDivider />
|
<SchemaSettingsDivider />
|
||||||
<SchemaSettingsRemove
|
<SchemaSettingsRemove
|
||||||
removeParentsIfNoChildren
|
removeParentsIfNoChildren
|
||||||
|
@ -17,6 +17,7 @@ import {
|
|||||||
useACLRoleContext,
|
useACLRoleContext,
|
||||||
useSchemaInitializer,
|
useSchemaInitializer,
|
||||||
useSchemaInitializerItem,
|
useSchemaInitializerItem,
|
||||||
|
useToken,
|
||||||
} from '@nocobase/client';
|
} from '@nocobase/client';
|
||||||
import React, { useCallback, useContext } from 'react';
|
import React, { useCallback, useContext } from 'react';
|
||||||
import { ChartConfigContext } from '../configure';
|
import { ChartConfigContext } from '../configure';
|
||||||
@ -103,6 +104,7 @@ export const chartInitializers = new CompatibleSchemaInitializer(
|
|||||||
export const ChartV2BlockInitializer: React.FC = () => {
|
export const ChartV2BlockInitializer: React.FC = () => {
|
||||||
const itemConfig = useSchemaInitializerItem();
|
const itemConfig = useSchemaInitializerItem();
|
||||||
const { insert } = useSchemaInitializer();
|
const { insert } = useSchemaInitializer();
|
||||||
|
const { token } = useToken();
|
||||||
return (
|
return (
|
||||||
<SchemaInitializerItem
|
<SchemaInitializerItem
|
||||||
{...itemConfig}
|
{...itemConfig}
|
||||||
@ -113,6 +115,9 @@ export const ChartV2BlockInitializer: React.FC = () => {
|
|||||||
'x-component': 'CardItem',
|
'x-component': 'CardItem',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
name: 'charts',
|
name: 'charts',
|
||||||
|
bodyStyle: {
|
||||||
|
padding: `${token.paddingLG}px ${token.paddingLG}px 0`,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'x-designer': 'ChartV2BlockDesigner',
|
'x-designer': 'ChartV2BlockDesigner',
|
||||||
properties: {
|
properties: {
|
||||||
|
@ -11,25 +11,38 @@ import React, { useContext, useEffect, useRef } from 'react';
|
|||||||
import { ChartRendererContext } from '../../renderer';
|
import { ChartRendererContext } from '../../renderer';
|
||||||
|
|
||||||
export const getAntChart = (Component: React.FC<any>) => (props: any) => {
|
export const getAntChart = (Component: React.FC<any>) => (props: any) => {
|
||||||
|
const { size = {} } = props;
|
||||||
|
let { height: fixedHeight } = props;
|
||||||
|
if (!fixedHeight && size.type === 'fixed') {
|
||||||
|
fixedHeight = size.fixed;
|
||||||
|
}
|
||||||
const { service } = useContext(ChartRendererContext);
|
const { service } = useContext(ChartRendererContext);
|
||||||
const chartRef = useRef(null);
|
const chartRef = useRef(null);
|
||||||
const [height, setHeight] = React.useState<number>(0);
|
const [height, setHeight] = React.useState<number>(0);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const el = chartRef.current;
|
const el = chartRef.current;
|
||||||
if (!el || service.loading === true || props.height) {
|
if (!el || service.loading === true || fixedHeight) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let ratio = 0;
|
||||||
|
if (size.type === 'ratio' && size.ratio?.width && size.ratio?.height) {
|
||||||
|
ratio = size.ratio.height / size.ratio.width;
|
||||||
|
}
|
||||||
const observer = new ResizeObserver((entries) => {
|
const observer = new ResizeObserver((entries) => {
|
||||||
entries.forEach((entry) => {
|
entries.forEach((entry) => {
|
||||||
|
if (ratio) {
|
||||||
|
setHeight(entry.contentRect.width * ratio);
|
||||||
|
return;
|
||||||
|
}
|
||||||
setHeight(entry.contentRect.height);
|
setHeight(entry.contentRect.height);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
observer.observe(el);
|
observer.observe(el);
|
||||||
return () => observer.disconnect();
|
return () => observer.disconnect();
|
||||||
}, [service.loading, props.height]);
|
}, [service.loading, fixedHeight, size.type, size.ratio?.width, size.ratio?.height]);
|
||||||
return (
|
return (
|
||||||
<div ref={chartRef} style={height ? { height: `${props.height || height}px` } : {}}>
|
<div ref={chartRef} style={height ? { height: `${fixedHeight || height}px` } : {}}>
|
||||||
<Component {...props} {...(height ? { height: props.height || height } : {})} />
|
<Component {...props} {...(height ? { height: fixedHeight || height } : {})} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -9,10 +9,95 @@
|
|||||||
|
|
||||||
import config, { FieldConfigProps } from '../configs';
|
import config, { FieldConfigProps } from '../configs';
|
||||||
const { booleanField } = config;
|
const { booleanField } = config;
|
||||||
|
import { lang } from '../../locale';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
isStack: (props: FieldConfigProps) => booleanField({ name: 'isStack', title: 'isStack', ...props }),
|
isStack: (props: FieldConfigProps) => booleanField({ name: 'isStack', title: 'isStack', ...props }),
|
||||||
smooth: (props: FieldConfigProps) => booleanField({ name: 'smooth', title: 'smooth', ...props }),
|
smooth: (props: FieldConfigProps) => booleanField({ name: 'smooth', title: 'smooth', ...props }),
|
||||||
isPercent: (props: FieldConfigProps) => booleanField({ name: 'isPercent', title: 'isPercent', ...props }),
|
isPercent: (props: FieldConfigProps) => booleanField({ name: 'isPercent', title: 'isPercent', ...props }),
|
||||||
isGroup: (props: FieldConfigProps) => booleanField({ name: 'isGroup', title: 'isGroup', ...props }),
|
isGroup: (props: FieldConfigProps) => booleanField({ name: 'isGroup', title: 'isGroup', ...props }),
|
||||||
|
size: () => ({
|
||||||
|
size: {
|
||||||
|
title: lang('Size'),
|
||||||
|
type: 'object',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Space',
|
||||||
|
properties: {
|
||||||
|
type: {
|
||||||
|
'x-component': 'Select',
|
||||||
|
'x-component-props': {
|
||||||
|
allowClear: false,
|
||||||
|
},
|
||||||
|
default: 'ratio',
|
||||||
|
enum: [
|
||||||
|
{
|
||||||
|
label: lang('Aspect ratio'),
|
||||||
|
value: 'ratio',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: lang('Fixed height'),
|
||||||
|
value: 'fixed',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
fixed: {
|
||||||
|
type: 'number',
|
||||||
|
'x-component': 'InputNumber',
|
||||||
|
'x-component-props': {
|
||||||
|
min: 0,
|
||||||
|
addonAfter: 'px',
|
||||||
|
},
|
||||||
|
'x-reactions': [
|
||||||
|
{
|
||||||
|
dependencies: ['.type'],
|
||||||
|
fulfill: {
|
||||||
|
state: {
|
||||||
|
visible: "{{$deps[0] === 'fixed'}}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
ratio: {
|
||||||
|
type: 'object',
|
||||||
|
'x-component': 'Space',
|
||||||
|
'x-reactions': [
|
||||||
|
{
|
||||||
|
dependencies: ['.type'],
|
||||||
|
fulfill: {
|
||||||
|
state: {
|
||||||
|
visible: "{{$deps[0] === 'ratio'}}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
properties: {
|
||||||
|
width: {
|
||||||
|
type: 'number',
|
||||||
|
'x-component': 'InputNumber',
|
||||||
|
'x-component-props': {
|
||||||
|
placeholder: lang('Width'),
|
||||||
|
min: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
colon: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Text',
|
||||||
|
'x-component-props': {
|
||||||
|
children: ':',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: 'number',
|
||||||
|
'x-component': 'InputNumber',
|
||||||
|
'x-component-props': {
|
||||||
|
placeholder: lang('Height'),
|
||||||
|
min: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
@ -17,7 +17,7 @@ export class G2PlotChart extends Chart {
|
|||||||
name,
|
name,
|
||||||
title,
|
title,
|
||||||
Component: getAntChart(Component),
|
Component: getAntChart(Component),
|
||||||
config: ['xField', 'yField', 'seriesField', ...(config || [])],
|
config: ['xField', 'yField', 'seriesField', 'size', ...(config || [])],
|
||||||
});
|
});
|
||||||
this.addConfigs(configs);
|
this.addConfigs(configs);
|
||||||
}
|
}
|
||||||
|
@ -147,11 +147,9 @@ export const ChartRendererProvider: React.FC<ChartRendererProps> = (props) => {
|
|||||||
return (
|
return (
|
||||||
<CollectionManagerProvider dataSource={dataSource}>
|
<CollectionManagerProvider dataSource={dataSource}>
|
||||||
<MaybeCollectionProvider collection={collection}>
|
<MaybeCollectionProvider collection={collection}>
|
||||||
<ConfigProvider card={{ style: { boxShadow: 'none' } }}>
|
<ChartRendererContext.Provider value={{ dataSource, collection, config, transform, service, query }}>
|
||||||
<ChartRendererContext.Provider value={{ dataSource, collection, config, transform, service, query }}>
|
{props.children}
|
||||||
{props.children}
|
</ChartRendererContext.Provider>
|
||||||
</ChartRendererContext.Provider>
|
|
||||||
</ConfigProvider>
|
|
||||||
</MaybeCollectionProvider>
|
</MaybeCollectionProvider>
|
||||||
</CollectionManagerProvider>
|
</CollectionManagerProvider>
|
||||||
);
|
);
|
||||||
|
@ -87,5 +87,12 @@
|
|||||||
"Show border": "Show border",
|
"Show border": "Show border",
|
||||||
"Transformation tip": "Fields allow multiple transformations, applied sequentially. Pay attention to data type changes after each transformation. Drag-and-drop functionality enables adjustment of transformation order.",
|
"Transformation tip": "Fields allow multiple transformations, applied sequentially. Pay attention to data type changes after each transformation. Drag-and-drop functionality enables adjustment of transformation order.",
|
||||||
"Type conversion": "Type conversion",
|
"Type conversion": "Type conversion",
|
||||||
"Transformer": "Transformer"
|
"Transformer": "Transformer",
|
||||||
|
"Size": "Size",
|
||||||
|
"Width": "Width",
|
||||||
|
"Height": "Height",
|
||||||
|
"Aspect ratio": "Aspect ratio",
|
||||||
|
"Fixed height": "Fixed height",
|
||||||
|
"Show background": "Show background",
|
||||||
|
"Show padding": "Show padding"
|
||||||
}
|
}
|
||||||
|
@ -88,5 +88,12 @@
|
|||||||
"Show border": "显示边框",
|
"Show border": "显示边框",
|
||||||
"Transformation tip": "一个字段可以应用多次转换,会按照顺序执行,请注意每次转换后的数据类型,拖动可以调整转换顺序。",
|
"Transformation tip": "一个字段可以应用多次转换,会按照顺序执行,请注意每次转换后的数据类型,拖动可以调整转换顺序。",
|
||||||
"Type conversion": "类型转换",
|
"Type conversion": "类型转换",
|
||||||
"Transformer": "转换方法"
|
"Transformer": "转换方法",
|
||||||
|
"Size": "尺寸",
|
||||||
|
"Width": "宽",
|
||||||
|
"Height": "高",
|
||||||
|
"Aspect ratio": "宽高比",
|
||||||
|
"Fixed height": "固定高度",
|
||||||
|
"Show background": "显示背景",
|
||||||
|
"Show padding": "显示内边距"
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,6 @@ export const Mobile = () => {
|
|||||||
marginBlock: 18,
|
marginBlock: 18,
|
||||||
borderRadiusBlock: 0,
|
borderRadiusBlock: 0,
|
||||||
boxShadowBlock: 'none',
|
boxShadowBlock: 'none',
|
||||||
borderBottomBlock: '1px solid var(--adm-color-border)',
|
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user