@report-designer/designer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/band-metadata.d.ts +8 -0
- package/dist/band-metadata.d.ts.map +1 -0
- package/dist/band-metadata.js +75 -0
- package/dist/band-metadata.js.map +1 -0
- package/dist/component-factory.d.ts +9 -0
- package/dist/component-factory.d.ts.map +1 -0
- package/dist/component-factory.js +141 -0
- package/dist/component-factory.js.map +1 -0
- package/dist/component-palette-model.d.ts +14 -0
- package/dist/component-palette-model.d.ts.map +1 -0
- package/dist/component-palette-model.js +21 -0
- package/dist/component-palette-model.js.map +1 -0
- package/dist/components/Canvas.d.ts +5 -0
- package/dist/components/Canvas.d.ts.map +1 -0
- package/dist/components/Canvas.js +2428 -0
- package/dist/components/Canvas.js.map +1 -0
- package/dist/components/ConditionalFormatManager.d.ts +8 -0
- package/dist/components/ConditionalFormatManager.d.ts.map +1 -0
- package/dist/components/ConditionalFormatManager.js +135 -0
- package/dist/components/ConditionalFormatManager.js.map +1 -0
- package/dist/components/Designer.d.ts +22 -0
- package/dist/components/Designer.d.ts.map +1 -0
- package/dist/components/Designer.js +115 -0
- package/dist/components/Designer.js.map +1 -0
- package/dist/components/ExpressionEditor.d.ts +10 -0
- package/dist/components/ExpressionEditor.d.ts.map +1 -0
- package/dist/components/ExpressionEditor.js +203 -0
- package/dist/components/ExpressionEditor.js.map +1 -0
- package/dist/components/LeftPanel.d.ts +11 -0
- package/dist/components/LeftPanel.d.ts.map +1 -0
- package/dist/components/LeftPanel.js +551 -0
- package/dist/components/LeftPanel.js.map +1 -0
- package/dist/components/PropertyEditor.d.ts +6 -0
- package/dist/components/PropertyEditor.d.ts.map +1 -0
- package/dist/components/PropertyEditor.js +1002 -0
- package/dist/components/PropertyEditor.js.map +1 -0
- package/dist/components/RibbonToolbar.d.ts +3 -0
- package/dist/components/RibbonToolbar.d.ts.map +1 -0
- package/dist/components/RibbonToolbar.js +179 -0
- package/dist/components/RibbonToolbar.js.map +1 -0
- package/dist/components/TextFormatEditor.d.ts +13 -0
- package/dist/components/TextFormatEditor.d.ts.map +1 -0
- package/dist/components/TextFormatEditor.js +199 -0
- package/dist/components/TextFormatEditor.js.map +1 -0
- package/dist/components/TextStyleLibraryDialog.d.ts +8 -0
- package/dist/components/TextStyleLibraryDialog.d.ts.map +1 -0
- package/dist/components/TextStyleLibraryDialog.js +367 -0
- package/dist/components/TextStyleLibraryDialog.js.map +1 -0
- package/dist/components/canvas/DesignerCanvasFrame.d.ts +10 -0
- package/dist/components/canvas/DesignerCanvasFrame.d.ts.map +1 -0
- package/dist/components/canvas/DesignerCanvasFrame.js +22 -0
- package/dist/components/canvas/DesignerCanvasFrame.js.map +1 -0
- package/dist/components/chart/ChartAxesPanel.d.ts +12 -0
- package/dist/components/chart/ChartAxesPanel.d.ts.map +1 -0
- package/dist/components/chart/ChartAxesPanel.js +71 -0
- package/dist/components/chart/ChartAxesPanel.js.map +1 -0
- package/dist/components/chart/ChartDataPanel.d.ts +21 -0
- package/dist/components/chart/ChartDataPanel.d.ts.map +1 -0
- package/dist/components/chart/ChartDataPanel.js +80 -0
- package/dist/components/chart/ChartDataPanel.js.map +1 -0
- package/dist/components/chart/ChartLabelPanel.d.ts +12 -0
- package/dist/components/chart/ChartLabelPanel.d.ts.map +1 -0
- package/dist/components/chart/ChartLabelPanel.js +34 -0
- package/dist/components/chart/ChartLabelPanel.js.map +1 -0
- package/dist/components/chart/ChartLegendPanel.d.ts +12 -0
- package/dist/components/chart/ChartLegendPanel.d.ts.map +1 -0
- package/dist/components/chart/ChartLegendPanel.js +48 -0
- package/dist/components/chart/ChartLegendPanel.js.map +1 -0
- package/dist/components/chart/ChartPropertyPanel.d.ts +26 -0
- package/dist/components/chart/ChartPropertyPanel.d.ts.map +1 -0
- package/dist/components/chart/ChartPropertyPanel.js +119 -0
- package/dist/components/chart/ChartPropertyPanel.js.map +1 -0
- package/dist/components/chart/ChartThemePanel.d.ts +9 -0
- package/dist/components/chart/ChartThemePanel.d.ts.map +1 -0
- package/dist/components/chart/ChartThemePanel.js +21 -0
- package/dist/components/chart/ChartThemePanel.js.map +1 -0
- package/dist/components/chart/ChartTitlePanel.d.ts +10 -0
- package/dist/components/chart/ChartTitlePanel.d.ts.map +1 -0
- package/dist/components/chart/ChartTitlePanel.js +45 -0
- package/dist/components/chart/ChartTitlePanel.js.map +1 -0
- package/dist/components/chart/ChartTypeStylePanel.d.ts +11 -0
- package/dist/components/chart/ChartTypeStylePanel.d.ts.map +1 -0
- package/dist/components/chart/ChartTypeStylePanel.js +37 -0
- package/dist/components/chart/ChartTypeStylePanel.js.map +1 -0
- package/dist/components/chart/ColorPaletteEditor.d.ts +10 -0
- package/dist/components/chart/ColorPaletteEditor.d.ts.map +1 -0
- package/dist/components/chart/ColorPaletteEditor.js +18 -0
- package/dist/components/chart/ColorPaletteEditor.js.map +1 -0
- package/dist/components/chart/chart-options.d.ts +119 -0
- package/dist/components/chart/chart-options.d.ts.map +1 -0
- package/dist/components/chart/chart-options.js +217 -0
- package/dist/components/chart/chart-options.js.map +1 -0
- package/dist/components/dialogs/BandWizardDialog.d.ts +8 -0
- package/dist/components/dialogs/BandWizardDialog.d.ts.map +1 -0
- package/dist/components/dialogs/BandWizardDialog.js +54 -0
- package/dist/components/dialogs/BandWizardDialog.js.map +1 -0
- package/dist/components/dialogs/GroupWizardDialog.d.ts +8 -0
- package/dist/components/dialogs/GroupWizardDialog.d.ts.map +1 -0
- package/dist/components/dialogs/GroupWizardDialog.js +70 -0
- package/dist/components/dialogs/GroupWizardDialog.js.map +1 -0
- package/dist/components/dialogs/JsonDataSourceDialog.d.ts +8 -0
- package/dist/components/dialogs/JsonDataSourceDialog.d.ts.map +1 -0
- package/dist/components/dialogs/JsonDataSourceDialog.js +67 -0
- package/dist/components/dialogs/JsonDataSourceDialog.js.map +1 -0
- package/dist/components/dialogs/PageSetupDialog.d.ts +8 -0
- package/dist/components/dialogs/PageSetupDialog.d.ts.map +1 -0
- package/dist/components/dialogs/PageSetupDialog.js +145 -0
- package/dist/components/dialogs/PageSetupDialog.js.map +1 -0
- package/dist/components/dialogs/dialog-utils.d.ts +6 -0
- package/dist/components/dialogs/dialog-utils.d.ts.map +1 -0
- package/dist/components/dialogs/dialog-utils.js +37 -0
- package/dist/components/dialogs/dialog-utils.js.map +1 -0
- package/dist/components/events/EventEditorDialog.d.ts +43 -0
- package/dist/components/events/EventEditorDialog.d.ts.map +1 -0
- package/dist/components/events/EventEditorDialog.js +271 -0
- package/dist/components/events/EventEditorDialog.js.map +1 -0
- package/dist/components/events/EventScriptEditor.d.ts +41 -0
- package/dist/components/events/EventScriptEditor.d.ts.map +1 -0
- package/dist/components/events/EventScriptEditor.js +140 -0
- package/dist/components/events/EventScriptEditor.js.map +1 -0
- package/dist/components/events/event-editor-utils.d.ts +18 -0
- package/dist/components/events/event-editor-utils.d.ts.map +1 -0
- package/dist/components/events/event-editor-utils.js +66 -0
- package/dist/components/events/event-editor-utils.js.map +1 -0
- package/dist/components/events/event-script-monaco.d.ts +74 -0
- package/dist/components/events/event-script-monaco.d.ts.map +1 -0
- package/dist/components/events/event-script-monaco.js +282 -0
- package/dist/components/events/event-script-monaco.js.map +1 -0
- package/dist/components/events/event-script-templates.d.ts +7 -0
- package/dist/components/events/event-script-templates.d.ts.map +1 -0
- package/dist/components/events/event-script-templates.js +100 -0
- package/dist/components/events/event-script-templates.js.map +1 -0
- package/dist/components/expression/ExpressionMonacoEditor.d.ts +16 -0
- package/dist/components/expression/ExpressionMonacoEditor.d.ts.map +1 -0
- package/dist/components/expression/ExpressionMonacoEditor.js +63 -0
- package/dist/components/expression/ExpressionMonacoEditor.js.map +1 -0
- package/dist/components/expression/InlineExpressionEditor.d.ts +10 -0
- package/dist/components/expression/InlineExpressionEditor.d.ts.map +1 -0
- package/dist/components/expression/InlineExpressionEditor.js +33 -0
- package/dist/components/expression/InlineExpressionEditor.js.map +1 -0
- package/dist/components/expression/expression-monaco.d.ts +34 -0
- package/dist/components/expression/expression-monaco.d.ts.map +1 -0
- package/dist/components/expression/expression-monaco.js +87 -0
- package/dist/components/expression/expression-monaco.js.map +1 -0
- package/dist/components/panels/DesignerLeftPanel.d.ts +11 -0
- package/dist/components/panels/DesignerLeftPanel.d.ts.map +1 -0
- package/dist/components/panels/DesignerLeftPanel.js +8 -0
- package/dist/components/panels/DesignerLeftPanel.js.map +1 -0
- package/dist/components/panels/DesignerPropertyPanel.d.ts +6 -0
- package/dist/components/panels/DesignerPropertyPanel.d.ts.map +1 -0
- package/dist/components/panels/DesignerPropertyPanel.js +441 -0
- package/dist/components/panels/DesignerPropertyPanel.js.map +1 -0
- package/dist/components/panels/PanelSearchBox.d.ts +9 -0
- package/dist/components/panels/PanelSearchBox.d.ts.map +1 -0
- package/dist/components/panels/PanelSearchBox.js +5 -0
- package/dist/components/panels/PanelSearchBox.js.map +1 -0
- package/dist/components/properties/BandPropertyGrid.d.ts +6 -0
- package/dist/components/properties/BandPropertyGrid.d.ts.map +1 -0
- package/dist/components/properties/BandPropertyGrid.js +504 -0
- package/dist/components/properties/BandPropertyGrid.js.map +1 -0
- package/dist/components/properties/BoxStyleEditors.d.ts +59 -0
- package/dist/components/properties/BoxStyleEditors.d.ts.map +1 -0
- package/dist/components/properties/BoxStyleEditors.js +87 -0
- package/dist/components/properties/BoxStyleEditors.js.map +1 -0
- package/dist/components/properties/FontEditor.d.ts +28 -0
- package/dist/components/properties/FontEditor.d.ts.map +1 -0
- package/dist/components/properties/FontEditor.js +22 -0
- package/dist/components/properties/FontEditor.js.map +1 -0
- package/dist/components/ribbon/DesignerRibbon.d.ts +3 -0
- package/dist/components/ribbon/DesignerRibbon.d.ts.map +1 -0
- package/dist/components/ribbon/DesignerRibbon.js +193 -0
- package/dist/components/ribbon/DesignerRibbon.js.map +1 -0
- package/dist/components/richtext/RichTextInlineEditor.d.ts +15 -0
- package/dist/components/richtext/RichTextInlineEditor.d.ts.map +1 -0
- package/dist/components/richtext/RichTextInlineEditor.js +94 -0
- package/dist/components/richtext/RichTextInlineEditor.js.map +1 -0
- package/dist/components/shell/DesignerShell.d.ts +12 -0
- package/dist/components/shell/DesignerShell.d.ts.map +1 -0
- package/dist/components/shell/DesignerShell.js +124 -0
- package/dist/components/shell/DesignerShell.js.map +1 -0
- package/dist/components/shell/DesignerStatusBar.d.ts +3 -0
- package/dist/components/shell/DesignerStatusBar.d.ts.map +1 -0
- package/dist/components/shell/DesignerStatusBar.js +23 -0
- package/dist/components/shell/DesignerStatusBar.js.map +1 -0
- package/dist/components/tree/ReportTree.d.ts +3 -0
- package/dist/components/tree/ReportTree.d.ts.map +1 -0
- package/dist/components/tree/ReportTree.js +17 -0
- package/dist/components/tree/ReportTree.js.map +1 -0
- package/dist/data-source-fields.d.ts +14 -0
- package/dist/data-source-fields.d.ts.map +1 -0
- package/dist/data-source-fields.js +49 -0
- package/dist/data-source-fields.js.map +1 -0
- package/dist/data-source-paths.d.ts +10 -0
- package/dist/data-source-paths.d.ts.map +1 -0
- package/dist/data-source-paths.js +61 -0
- package/dist/data-source-paths.js.map +1 -0
- package/dist/expression/expression-catalog.d.ts +39 -0
- package/dist/expression/expression-catalog.d.ts.map +1 -0
- package/dist/expression/expression-catalog.js +127 -0
- package/dist/expression/expression-catalog.js.map +1 -0
- package/dist/expression/expression-preview.d.ts +11 -0
- package/dist/expression/expression-preview.d.ts.map +1 -0
- package/dist/expression/expression-preview.js +58 -0
- package/dist/expression/expression-preview.js.map +1 -0
- package/dist/expression/expression-validation.d.ts +12 -0
- package/dist/expression/expression-validation.d.ts.map +1 -0
- package/dist/expression/expression-validation.js +85 -0
- package/dist/expression/expression-validation.js.map +1 -0
- package/dist/expression/function-catalog.d.ts +21 -0
- package/dist/expression/function-catalog.d.ts.map +1 -0
- package/dist/expression/function-catalog.js +96 -0
- package/dist/expression/function-catalog.js.map +1 -0
- package/dist/i18n/DesignerI18nProvider.d.ts +11 -0
- package/dist/i18n/DesignerI18nProvider.d.ts.map +1 -0
- package/dist/i18n/DesignerI18nProvider.js +32 -0
- package/dist/i18n/DesignerI18nProvider.js.map +1 -0
- package/dist/i18n/index.d.ts +3 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +2 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n/messages.d.ts +5 -0
- package/dist/i18n/messages.d.ts.map +1 -0
- package/dist/i18n/messages.js +1383 -0
- package/dist/i18n/messages.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/page-settings.d.ts +21 -0
- package/dist/page-settings.d.ts.map +1 -0
- package/dist/page-settings.js +66 -0
- package/dist/page-settings.js.map +1 -0
- package/dist/report-structure.d.ts +20 -0
- package/dist/report-structure.d.ts.map +1 -0
- package/dist/report-structure.js +219 -0
- package/dist/report-structure.js.map +1 -0
- package/dist/store/designer-store.d.ts +161 -0
- package/dist/store/designer-store.d.ts.map +1 -0
- package/dist/store/designer-store.js +1851 -0
- package/dist/store/designer-store.js.map +1 -0
- package/dist/table/table-structure.d.ts +50 -0
- package/dist/table/table-structure.d.ts.map +1 -0
- package/dist/table/table-structure.js +251 -0
- package/dist/table/table-structure.js.map +1 -0
- package/dist/text-style-application.d.ts +11 -0
- package/dist/text-style-application.d.ts.map +1 -0
- package/dist/text-style-application.js +135 -0
- package/dist/text-style-application.js.map +1 -0
- package/dist/text-style-bindings.d.ts +16 -0
- package/dist/text-style-bindings.d.ts.map +1 -0
- package/dist/text-style-bindings.js +549 -0
- package/dist/text-style-bindings.js.map +1 -0
- package/package.json +70 -0
|
@@ -0,0 +1,1002 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React, { useMemo, useState } from 'react';
|
|
3
|
+
import { Form, Input, InputNumber, Select, Switch, ColorPicker, Collapse, Space, Button, Divider, Typography, Tooltip } from 'antd';
|
|
4
|
+
import { AlignCenterOutlined, AlignLeftOutlined, AlignRightOutlined, EditOutlined, DisconnectOutlined, UploadOutlined, } from '@ant-design/icons';
|
|
5
|
+
import { useDesignerStore } from '../store/designer-store';
|
|
6
|
+
import { getReportFontOptions, supportsComponentStyle } from '@report-designer/core';
|
|
7
|
+
import { formatUnitValue, getUnitStep, parseUnitValue } from '../page-settings';
|
|
8
|
+
import { ExpressionEditor } from './ExpressionEditor';
|
|
9
|
+
import { normalizeTable } from '../table/table-structure';
|
|
10
|
+
import { isTextStylePropertyLocked } from '../text-style-application';
|
|
11
|
+
import { TextFormatEditor } from './TextFormatEditor';
|
|
12
|
+
import { useDesignerI18n } from '../i18n';
|
|
13
|
+
import { EventEditorDialog } from './events/EventEditorDialog';
|
|
14
|
+
import { buildEventEditorDataContext } from './events/event-editor-utils';
|
|
15
|
+
import { BorderEditor, PaddingEditor } from './properties/BoxStyleEditors';
|
|
16
|
+
import { FontEditor } from './properties/FontEditor';
|
|
17
|
+
import { BARCODE_FORMATS, QR_CODE_FORMATS } from '@report-designer/viewer';
|
|
18
|
+
import { isComponentNameAvailable, normalizeComponentName } from '../report-structure';
|
|
19
|
+
import { createArrayPathOptions } from '../data-source-paths';
|
|
20
|
+
import { buildChartPropertyItems } from './chart/ChartPropertyPanel';
|
|
21
|
+
const NO_CONDITIONAL_FORMAT = '__none__';
|
|
22
|
+
const EMPTY_DATA_PATHS = [];
|
|
23
|
+
export const PropertyEditor = ({ expressionExtensions }) => {
|
|
24
|
+
const { locale, t: globalT } = useDesignerI18n();
|
|
25
|
+
const t = React.useMemo(() => createPropertyT(locale), [locale]);
|
|
26
|
+
const template = useDesignerStore(s => s.template);
|
|
27
|
+
const currentPageId = useDesignerStore(s => s.currentPageId);
|
|
28
|
+
const selectedComponentIds = useDesignerStore(s => s.selectedComponentIds);
|
|
29
|
+
const updateComponent = useDesignerStore(s => s.updateComponent);
|
|
30
|
+
const updateSelectedTable = useDesignerStore(s => s.updateSelectedTable);
|
|
31
|
+
const applySelectedStyle = useDesignerStore(s => s.applySelectedStyle);
|
|
32
|
+
const unbindSelectedStyle = useDesignerStore(s => s.unbindSelectedStyle);
|
|
33
|
+
const applySelectedConditionalFormat = useDesignerStore(s => s.applySelectedConditionalFormat);
|
|
34
|
+
const replaceComponentEvents = useDesignerStore(s => s.replaceComponentEvents);
|
|
35
|
+
const openConditionalFormatLibrary = useDesignerStore(s => s.openConditionalFormatLibrary);
|
|
36
|
+
const reportUnit = useDesignerStore(s => s.reportUnit);
|
|
37
|
+
const pendingEventEditorTarget = useDesignerStore(s => s.pendingEventEditorTarget);
|
|
38
|
+
const consumeEventEditorTarget = useDesignerStore(s => s.consumeEventEditorTarget);
|
|
39
|
+
const runtimeDataSources = useDesignerStore(s => s.dataSources);
|
|
40
|
+
const [eventEditorDataTemplate, setEventEditorDataTemplate] = React.useState(null);
|
|
41
|
+
const { component, bandId } = useMemo(() => {
|
|
42
|
+
if (selectedComponentIds.length !== 1)
|
|
43
|
+
return { component: null, bandId: null };
|
|
44
|
+
const page = template.pages.find(p => p.id === currentPageId);
|
|
45
|
+
if (!page)
|
|
46
|
+
return { component: null, bandId: null };
|
|
47
|
+
for (const band of page.bands) {
|
|
48
|
+
const comp = findComponentInTree(band.components, selectedComponentIds[0]);
|
|
49
|
+
if (comp)
|
|
50
|
+
return { component: comp, bandId: band.id };
|
|
51
|
+
}
|
|
52
|
+
return { component: null, bandId: null };
|
|
53
|
+
}, [template, currentPageId, selectedComponentIds]);
|
|
54
|
+
const componentId = component?.id;
|
|
55
|
+
const [expressionTarget, setExpressionTarget] = useState(null);
|
|
56
|
+
const [eventEditorOpen, setEventEditorOpen] = useState(false);
|
|
57
|
+
const [eventEditorTarget, setEventEditorTarget] = useState(null);
|
|
58
|
+
const [componentNameError, setComponentNameError] = useState(null);
|
|
59
|
+
const unitStep = getUnitStep(reportUnit);
|
|
60
|
+
const fineUnitStep = getUnitStep(reportUnit, 'fine');
|
|
61
|
+
const pendingTarget = pendingEventEditorTarget?.ownerType === 'component' && pendingEventEditorTarget.ownerId === component?.id
|
|
62
|
+
? pendingEventEditorTarget
|
|
63
|
+
: null;
|
|
64
|
+
React.useEffect(() => {
|
|
65
|
+
if (!pendingTarget)
|
|
66
|
+
return;
|
|
67
|
+
setEventEditorTarget(pendingTarget);
|
|
68
|
+
setEventEditorOpen(true);
|
|
69
|
+
consumeEventEditorTarget(pendingTarget.requestId);
|
|
70
|
+
}, [consumeEventEditorTarget, pendingTarget]);
|
|
71
|
+
React.useEffect(() => {
|
|
72
|
+
setComponentNameError(null);
|
|
73
|
+
}, [component?.id]);
|
|
74
|
+
React.useEffect(() => {
|
|
75
|
+
if (!eventEditorOpen)
|
|
76
|
+
return;
|
|
77
|
+
setEventEditorDataTemplate(template);
|
|
78
|
+
}, [eventEditorOpen, template]);
|
|
79
|
+
const dictionaryItems = React.useMemo(() => (eventEditorOpen && eventEditorDataTemplate ? buildDictionaryEventItems(eventEditorDataTemplate) : []), [eventEditorDataTemplate, eventEditorOpen]);
|
|
80
|
+
const componentItems = React.useMemo(() => (eventEditorOpen && eventEditorDataTemplate ? buildComponentEventItems(eventEditorDataTemplate) : []), [eventEditorDataTemplate, eventEditorOpen]);
|
|
81
|
+
const currentPage = React.useMemo(() => template.pages.find(p => p.id === currentPageId), [currentPageId, template.pages]);
|
|
82
|
+
const bandDataPathSignature = React.useMemo(() => currentPage?.bands.map(b => b.dataBand?.dataSourceId ?? b.dataSource ?? '').join('|') ?? '', [currentPage?.bands]);
|
|
83
|
+
const bandDataPaths = React.useMemo(() => currentPage?.bands.reduce((acc, b) => {
|
|
84
|
+
const dataSourceId = b.dataBand?.dataSourceId ?? b.dataSource;
|
|
85
|
+
if (dataSourceId && !acc.includes(dataSourceId))
|
|
86
|
+
acc.push(dataSourceId);
|
|
87
|
+
return acc;
|
|
88
|
+
}, []) ?? EMPTY_DATA_PATHS, [bandDataPathSignature]);
|
|
89
|
+
const dataSourceOptions = React.useMemo(() => createArrayPathOptions(template.dataSources, runtimeDataSources, bandDataPaths), [template.dataSources, runtimeDataSources, bandDataPaths]);
|
|
90
|
+
const reportFontOptions = React.useMemo(() => getReportFontOptions(template.fonts), [template.fonts]);
|
|
91
|
+
const handleChange = React.useCallback((field, value) => {
|
|
92
|
+
if (!componentId || !bandId || !currentPageId)
|
|
93
|
+
return;
|
|
94
|
+
const currentBand = useDesignerStore.getState().template.pages
|
|
95
|
+
.find(p => p.id === currentPageId)
|
|
96
|
+
?.bands.find(b => b.id === bandId);
|
|
97
|
+
const currentComponent = currentBand ? findComponentInTree(currentBand.components, componentId) : null;
|
|
98
|
+
updateComponent(currentPageId, bandId, componentId, { [field]: value }, { [field]: currentComponent?.[field] });
|
|
99
|
+
}, [bandId, componentId, currentPageId, updateComponent]);
|
|
100
|
+
const handleChangeMany = React.useCallback((updates) => {
|
|
101
|
+
if (!componentId || !bandId || !currentPageId)
|
|
102
|
+
return;
|
|
103
|
+
const currentBand = useDesignerStore.getState().template.pages
|
|
104
|
+
.find(p => p.id === currentPageId)
|
|
105
|
+
?.bands.find(b => b.id === bandId);
|
|
106
|
+
const currentComponent = currentBand ? findComponentInTree(currentBand.components, componentId) : null;
|
|
107
|
+
const previous = Object.fromEntries(Object.keys(updates).map(field => [field, currentComponent?.[field]]));
|
|
108
|
+
updateComponent(currentPageId, bandId, componentId, updates, previous);
|
|
109
|
+
}, [bandId, componentId, currentPageId, updateComponent]);
|
|
110
|
+
if (selectedComponentIds.length === 0) {
|
|
111
|
+
return (_jsx("div", { style: { padding: 16, textAlign: 'center', color: '#999', fontSize: 13 }, children: t('selectComponent') }));
|
|
112
|
+
}
|
|
113
|
+
if (selectedComponentIds.length > 1) {
|
|
114
|
+
return (_jsx("div", { style: { padding: 16, textAlign: 'center', color: '#999', fontSize: 13 }, children: t('selectedComponents', { count: selectedComponentIds.length }) }));
|
|
115
|
+
}
|
|
116
|
+
if (!component || !bandId)
|
|
117
|
+
return null;
|
|
118
|
+
const comp = component;
|
|
119
|
+
const handleNameChange = (value) => {
|
|
120
|
+
const name = normalizeComponentName(value);
|
|
121
|
+
if (!name) {
|
|
122
|
+
setComponentNameError(t('componentNameRequired'));
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (name && !isComponentNameAvailable(template, name, component.id)) {
|
|
126
|
+
setComponentNameError(t('componentNameDuplicate'));
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
setComponentNameError(null);
|
|
130
|
+
handleChange('name', value);
|
|
131
|
+
};
|
|
132
|
+
const openFieldExpressionEditor = (field, label) => {
|
|
133
|
+
setExpressionTarget({ field, label });
|
|
134
|
+
};
|
|
135
|
+
// ---- Border helpers ----
|
|
136
|
+
const border = normalizeOptionalBorder(comp.border);
|
|
137
|
+
// ---- Font helpers ----
|
|
138
|
+
const font = comp.font ?? { family: '', size: 12, bold: false, italic: false, underline: false, strikethrough: false, color: '#000000' };
|
|
139
|
+
const handleFontField = (field, value) => {
|
|
140
|
+
handleChange('font', { ...font, [field]: value });
|
|
141
|
+
};
|
|
142
|
+
const format = (comp.format ?? { type: 'none' });
|
|
143
|
+
// ---- Padding helpers ----
|
|
144
|
+
const padding = normalizeOptionalPadding(comp.padding);
|
|
145
|
+
const supportsSharedStyle = supportsComponentStyle(component);
|
|
146
|
+
const supportsFontProperties = ['text', 'barcode', 'checkbox', 'pagenumber', 'datetime', 'table'].includes(component.type);
|
|
147
|
+
const supportsBorderProperties = ['text', 'image', 'chart', 'barcode', 'qrcode', 'checkbox', 'panel', 'pagenumber', 'datetime', 'table'].includes(component.type);
|
|
148
|
+
const supportsAppearanceProperties = ['text', 'image', 'chart', 'barcode', 'qrcode', 'checkbox', 'richtext', 'panel', 'subreport', 'pagenumber', 'datetime', 'table'].includes(component.type);
|
|
149
|
+
const supportsForegroundColor = component.type === 'barcode' || component.type === 'qrcode' || component.type === 'checkbox';
|
|
150
|
+
const isTextStyleLocked = (pathOrPrefix) => (supportsSharedStyle ? isTextStylePropertyLocked(component, pathOrPrefix) : false);
|
|
151
|
+
const backgroundLocked = isTextStyleLocked('backgroundColor');
|
|
152
|
+
return (_jsxs("div", { style: { padding: 8 }, children: [_jsx(Collapse, { defaultActiveKey: ['general', 'position', 'behavior', 'text', 'font', 'border', 'appearance', 'events', 'table', 'line', 'shape', 'pagenumber', 'datetime', 'chartBasic', 'chartData'], size: "small", items: [
|
|
153
|
+
// ---- 基本信息 ----
|
|
154
|
+
{
|
|
155
|
+
key: 'general',
|
|
156
|
+
label: t('general'),
|
|
157
|
+
children: (_jsxs(Form, { layout: "horizontal", size: "small", labelCol: { span: 8 }, wrapperCol: { span: 16 }, children: [_jsx(Form.Item, { label: t('name'), validateStatus: componentNameError ? 'error' : undefined, help: componentNameError, children: _jsx(Input, { "aria-label": t('name'), value: comp.name || '', onChange: (e) => handleNameChange(e.target.value), size: "small", placeholder: t('componentName') }) }), _jsx(Form.Item, { label: t('type'), children: _jsx(Input, { "aria-label": t('type'), value: comp.type, size: "small", disabled: true }) }), supportsSharedStyle ? (_jsx(Form.Item, { label: t('textStyle'), children: _jsxs(Space.Compact, { "data-testid": "text-style-select-row", style: { width: '100%', minWidth: 0 }, children: [_jsx(Select, { "data-testid": "text-style-select", "aria-label": t('textStyle'), value: comp.style, onChange: (value) => (value ? applySelectedStyle(value) : unbindSelectedStyle()), onClear: () => unbindSelectedStyle(), size: "small", style: { flex: 1, width: '100%', minWidth: 0 }, allowClear: true, virtual: false, placeholder: t('chooseStyle'), options: template.styles.map(style => ({ value: style.id, label: style.name })) }), _jsx(Tooltip, { title: t('unbindStyle'), children: _jsx(Button, { "aria-label": t('unbindStyle'), icon: _jsx(DisconnectOutlined, {}), onClick: unbindSelectedStyle, disabled: !comp.style, size: "small", style: { width: 32, flex: '0 0 32px' } }) })] }) })) : null] })),
|
|
158
|
+
},
|
|
159
|
+
// ---- 位置尺寸 ----
|
|
160
|
+
{
|
|
161
|
+
key: 'position',
|
|
162
|
+
label: t('position'),
|
|
163
|
+
children: (_jsxs(Form, { layout: "horizontal", size: "small", labelCol: { span: 8 }, wrapperCol: { span: 16 }, children: [_jsx(Form.Item, { label: "X", children: _jsx(InputNumber, { "aria-label": "X", value: formatUnitValue(comp.x, reportUnit), onChange: (v) => handleChange('x', parseUnitValue(v, reportUnit, comp.x)), size: "small", style: { width: '100%' }, step: unitStep }) }), _jsx(Form.Item, { label: "Y", children: _jsx(InputNumber, { "aria-label": "Y", value: formatUnitValue(comp.y, reportUnit), onChange: (v) => handleChange('y', parseUnitValue(v, reportUnit, comp.y)), size: "small", style: { width: '100%' }, step: unitStep }) }), _jsx(Form.Item, { label: t('width'), children: _jsx(InputNumber, { "aria-label": t('width'), value: formatUnitValue(comp.width, reportUnit), onChange: (v) => handleChange('width', parseUnitValue(v, reportUnit, comp.width)), size: "small", style: { width: '100%' }, step: unitStep, min: formatUnitValue(1, reportUnit) }) }), _jsx(Form.Item, { label: t('height'), children: _jsx(InputNumber, { "aria-label": t('height'), value: formatUnitValue(comp.height, reportUnit), onChange: (v) => handleChange('height', parseUnitValue(v, reportUnit, comp.height)), size: "small", style: { width: '100%' }, step: unitStep, min: formatUnitValue(1, reportUnit) }) })] })),
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
key: 'behavior',
|
|
167
|
+
label: t('behavior'),
|
|
168
|
+
children: (_jsxs(Form, { layout: "horizontal", size: "small", labelCol: { span: 8 }, wrapperCol: { span: 16 }, children: [_jsx(Form.Item, { label: t('visibleExpression'), children: _jsxs(Space.Compact, { style: { width: '100%' }, children: [_jsx(Input, { "aria-label": t('visibleExpression'), value: comp.visible || '', onChange: (event) => handleChange('visible', event.target.value), size: "small", placeholder: t('visibleExpressionPlaceholder') }), _jsx(Button, { "aria-label": t('openExpressionEditorFor', { field: t('visibleExpression') }), title: t('openExpressionEditorFor', { field: t('visibleExpression') }), icon: _jsx(EditOutlined, {}), onClick: () => openFieldExpressionEditor('visible', t('visibleExpression')), style: { width: 32 } })] }) }), _jsx(Form.Item, { label: t('enabledExpression'), children: _jsxs(Space.Compact, { style: { width: '100%' }, children: [_jsx(Input, { "aria-label": t('enabledExpression'), value: comp.enabledExpression || '', onChange: (event) => handleChange('enabledExpression', event.target.value), size: "small", placeholder: t('enabledExpressionPlaceholder') }), _jsx(Button, { "aria-label": t('openExpressionEditorFor', { field: t('enabledExpression') }), title: t('openExpressionEditorFor', { field: t('enabledExpression') }), icon: _jsx(EditOutlined, {}), onClick: () => openFieldExpressionEditor('enabledExpression', t('enabledExpression')), style: { width: 32 } })] }) }), _jsx(Form.Item, { label: t('printableExpression'), children: _jsxs(Space.Compact, { style: { width: '100%' }, children: [_jsx(Input, { "aria-label": t('printableExpression'), value: comp.printableExpression || '', onChange: (event) => handleChange('printableExpression', event.target.value), size: "small", placeholder: t('printableExpressionPlaceholder') }), _jsx(Button, { "aria-label": t('openExpressionEditorFor', { field: t('printableExpression') }), title: t('openExpressionEditorFor', { field: t('printableExpression') }), icon: _jsx(EditOutlined, {}), onClick: () => openFieldExpressionEditor('printableExpression', t('printableExpression')), style: { width: 32 } })] }) })] })),
|
|
169
|
+
},
|
|
170
|
+
// ---- 文本内容(图表不走此组,由下方 chartItems spread)----
|
|
171
|
+
component.type !== 'chart' ? {
|
|
172
|
+
key: 'text',
|
|
173
|
+
label: t('text'),
|
|
174
|
+
children: component.type === 'text' ? (_jsxs(Form, { size: "small", labelCol: { span: 6 }, wrapperCol: { span: 18 }, children: [_jsx(Form.Item, { label: t('textContent'), children: _jsxs(Space.Compact, { style: { width: '100%' }, children: [_jsx(Input, { "aria-label": t('textContent'), value: comp.text || '', onChange: (e) => handleChange('text', e.target.value), size: "small", placeholder: t('textContentPlaceholder') }), _jsx(Button, { "aria-label": t('openExpressionEditorFor', { field: t('textContent') }), title: t('openExpressionEditorFor', { field: t('textContent') }), icon: _jsx(EditOutlined, {}), onClick: () => openFieldExpressionEditor('text', t('textContent')), style: { width: 32 } })] }) }), _jsx(Form.Item, { label: t('conditionalFormat'), children: _jsxs(Space.Compact, { "data-testid": "conditional-format-select-row", style: { width: '100%', minWidth: 0 }, children: [_jsx(Select, { "data-testid": "conditional-format-select", "aria-label": t('conditionalFormat'), value: comp.conditionalFormat ?? undefined, onChange: (value) => applySelectedConditionalFormat(value === NO_CONDITIONAL_FORMAT ? undefined : value), size: "small", style: { flex: 1, width: '100%', minWidth: 0 }, virtual: false, placeholder: t('chooseConditionalFormat'), options: [
|
|
175
|
+
{ value: NO_CONDITIONAL_FORMAT, label: t('none') },
|
|
176
|
+
...template.conditionalFormats.map(format => ({ value: format.id, label: format.name })),
|
|
177
|
+
] }), _jsx(Tooltip, { title: t('manage'), children: _jsx(Button, { "aria-label": t('manage'), icon: _jsx(EditOutlined, {}), onClick: openConditionalFormatLibrary, size: "small", style: { width: 32, flex: '0 0 32px' } }) })] }) }), _jsx(Form.Item, { wrapperCol: { span: 24 }, style: { marginBottom: 8 }, children: _jsx("div", { "data-testid": "property-format-editor-full-width", style: { width: '100%', minWidth: 0 }, children: _jsx(TextFormatEditor, { value: format, onChange: (nextFormat) => handleChange('format', nextFormat), isFieldDisabled: isTextStyleLocked, labelWidth: 88, size: "small" }) }) }), _jsx(Form.Item, { label: t('horizontalAlign'), children: _jsx(HorizontalAlignButtons, { value: comp.textAlign || 'left', onChange: (value) => handleChange('textAlign', value), disabled: isTextStyleLocked('textAlign'), labels: {
|
|
178
|
+
left: t('alignLeft'),
|
|
179
|
+
center: t('alignCenter'),
|
|
180
|
+
right: t('alignRight'),
|
|
181
|
+
} }) }), _jsx(Form.Item, { label: t('verticalAlign'), children: _jsx(VerticalAlignButtons, { value: comp.verticalAlign || 'top', onChange: (value) => handleChange('verticalAlign', value), disabled: isTextStyleLocked('verticalAlign'), labels: {
|
|
182
|
+
top: t('verticalTop'),
|
|
183
|
+
middle: t('verticalMiddle'),
|
|
184
|
+
bottom: t('verticalBottom'),
|
|
185
|
+
} }) }), _jsx(Form.Item, { label: t('canGrow'), children: _jsx(Switch, { "aria-label": t('canGrow'), size: "small", checked: comp.canGrow || false, onChange: (v) => handleChange('canGrow', v), disabled: isTextStyleLocked('canGrow') }) }), _jsx(Form.Item, { label: t('canShrink'), children: _jsx(Switch, { "aria-label": t('canShrink'), size: "small", checked: comp.canShrink || false, onChange: (v) => handleChange('canShrink', v), disabled: isTextStyleLocked('canShrink') }) })] })) : (_jsx(ComponentContentProperties, { component: component, comp: comp, onChange: handleChange, onChangeMany: handleChangeMany, onOpenExpressionEditor: openFieldExpressionEditor, t: t, dataSourceOptions: dataSourceOptions, dataSourceDefinitions: template.dataSources })),
|
|
186
|
+
} : null,
|
|
187
|
+
// ---- 图表属性(扁平展开,取消原 chart 包装层)----
|
|
188
|
+
...(component.type === 'chart' ? buildChartPropertyItems({
|
|
189
|
+
chart: comp,
|
|
190
|
+
dataSourceOptions,
|
|
191
|
+
dataSourceDefinitions: template.dataSources,
|
|
192
|
+
reportFontOptions,
|
|
193
|
+
onChange: handleChange,
|
|
194
|
+
onChangeMany: handleChangeMany,
|
|
195
|
+
t,
|
|
196
|
+
}) : []),
|
|
197
|
+
// ---- 字体 ----
|
|
198
|
+
supportsFontProperties ? {
|
|
199
|
+
key: 'font',
|
|
200
|
+
label: t('font'),
|
|
201
|
+
children: (_jsx(FontEditor, { value: font, onChange: (next) => handleChange('font', next), reportFontOptions: reportFontOptions, sizeRange: [6, 72], disabled: (field) => isTextStyleLocked(`font.${field}`), labels: {
|
|
202
|
+
fontFamily: t('fontFamily'),
|
|
203
|
+
fontSize: t('fontSize'),
|
|
204
|
+
textColor: t('textColor'),
|
|
205
|
+
bold: t('bold'),
|
|
206
|
+
italic: t('italic'),
|
|
207
|
+
underline: t('underline'),
|
|
208
|
+
strike: t('strike'),
|
|
209
|
+
} })),
|
|
210
|
+
} : null,
|
|
211
|
+
// ---- 边框 ----
|
|
212
|
+
supportsBorderProperties ? {
|
|
213
|
+
key: 'border',
|
|
214
|
+
label: t('border'),
|
|
215
|
+
children: (_jsx(Form, { size: "small", labelCol: { span: 8 }, wrapperCol: { span: 16 }, children: _jsx(BorderEditor, { value: border, labels: propertyBorderLabels(t), onChange: nextBorder => handleChange('border', nextBorder), disabled: isTextStyleLocked, formatWidth: value => formatUnitValue(value, reportUnit), parseWidth: (value, fallback) => parseUnitValue(value, reportUnit, fallback), minWidth: formatUnitValue(0.1, reportUnit), maxWidth: formatUnitValue(5, reportUnit), step: fineUnitStep }) })),
|
|
216
|
+
} : null,
|
|
217
|
+
// ---- 外观 ----
|
|
218
|
+
supportsAppearanceProperties ? {
|
|
219
|
+
key: 'appearance',
|
|
220
|
+
label: t('appearance'),
|
|
221
|
+
children: (_jsxs(Form, { layout: "horizontal", size: "small", labelCol: { span: 8 }, wrapperCol: { span: 16 }, children: [supportsForegroundColor ? (_jsx(Form.Item, { label: t('foregroundColor'), children: _jsxs(Space.Compact, { style: { width: '100%' }, children: [_jsx(ColorPicker, { "aria-label": t('foregroundColorPicker'), size: "small", value: comp.foregroundColor || '#000000', onChange: (color) => handleChange('foregroundColor', color.toHexString()) }), _jsx(Input, { "aria-label": t('foregroundColor'), value: comp.foregroundColor || '#000000', onChange: (event) => handleChange('foregroundColor', event.target.value), size: "small", style: { width: '100%' }, placeholder: "#000000" })] }) })) : null, _jsx(Form.Item, { label: t('backgroundColor'), children: _jsx(ColorPicker, { "aria-label": t('backgroundColor'), size: "small", value: comp.backgroundColor || '#ffffff', onChange: (color) => handleChange('backgroundColor', color.toHexString()), onClear: () => handleChange('backgroundColor', undefined), allowClear: true, disabled: backgroundLocked }) }), _jsx(Divider, { style: { margin: '4px 0' } }), _jsx(PaddingEditor, { value: padding, labels: propertyPaddingLabels(t), onChange: nextPadding => handleChange('padding', nextPadding), disabled: isTextStyleLocked, formatValue: value => formatUnitValue(value, reportUnit), parseValue: (value, fallback) => parseUnitValue(value, reportUnit, fallback), min: 0, step: unitStep })] })),
|
|
222
|
+
} : null,
|
|
223
|
+
// ---- 表格 ----
|
|
224
|
+
component.type === 'table' ? {
|
|
225
|
+
key: 'table',
|
|
226
|
+
label: t('table'),
|
|
227
|
+
children: (_jsx(TablePropertyPanel, { table: normalizeTable(component), onChange: updateSelectedTable, t: t })),
|
|
228
|
+
} : null,
|
|
229
|
+
// ---- 线条 ----
|
|
230
|
+
component.type === 'line' ? {
|
|
231
|
+
key: 'line',
|
|
232
|
+
label: t('line'),
|
|
233
|
+
children: (_jsxs(Form, { size: "small", labelCol: { span: 8 }, wrapperCol: { span: 16 }, children: [_jsx(Form.Item, { label: t('color'), children: _jsx(ColorPicker, { size: "small", value: comp.lineColor || '#000000', onChange: (color) => handleChange('lineColor', color.toHexString()) }) }), _jsx(Form.Item, { label: t('lineWidth'), children: _jsx(InputNumber, { value: formatUnitValue(comp.lineWidth ?? 0.2, reportUnit), onChange: (v) => handleChange('lineWidth', parseUnitValue(v, reportUnit, comp.lineWidth ?? 0.2)), size: "small", style: { width: '100%' }, min: formatUnitValue(0.1, reportUnit), max: formatUnitValue(5, reportUnit), step: fineUnitStep }) }), _jsx(Form.Item, { label: t('lineStyle'), children: _jsx(Select, { value: comp.lineStyle || 'solid', onChange: (v) => handleChange('lineStyle', v), size: "small", style: { width: '100%' }, options: [
|
|
234
|
+
{ value: 'solid', label: t('borderSolid') },
|
|
235
|
+
{ value: 'dashed', label: t('borderDashed') },
|
|
236
|
+
{ value: 'dotted', label: t('borderDotted') },
|
|
237
|
+
] }) }), _jsx(Divider, { style: { margin: '4px 0' } }), _jsx("div", { style: { fontSize: 12, color: '#666', marginBottom: 4 }, children: t('lineEndpoints') }), _jsx(Form.Item, { label: t('startX'), children: _jsx(InputNumber, { value: formatUnitValue(comp.startX ?? 0, reportUnit), onChange: (v) => handleChange('startX', parseUnitValue(v, reportUnit, comp.startX ?? 0)), size: "small", style: { width: '100%' }, step: unitStep }) }), _jsx(Form.Item, { label: t('startY'), children: _jsx(InputNumber, { value: formatUnitValue(comp.startY ?? 0, reportUnit), onChange: (v) => handleChange('startY', parseUnitValue(v, reportUnit, comp.startY ?? 0)), size: "small", style: { width: '100%' }, step: unitStep }) }), _jsx(Form.Item, { label: t('endX'), children: _jsx(InputNumber, { value: formatUnitValue(comp.endX ?? comp.width, reportUnit), onChange: (v) => handleChange('endX', parseUnitValue(v, reportUnit, comp.endX ?? comp.width)), size: "small", style: { width: '100%' }, step: unitStep }) }), _jsx(Form.Item, { label: t('endY'), children: _jsx(InputNumber, { value: formatUnitValue(comp.endY ?? comp.height, reportUnit), onChange: (v) => handleChange('endY', parseUnitValue(v, reportUnit, comp.endY ?? comp.height)), size: "small", style: { width: '100%' }, step: unitStep }) })] })),
|
|
238
|
+
} : null,
|
|
239
|
+
// ---- 形状 ----
|
|
240
|
+
component.type === 'shape' ? {
|
|
241
|
+
key: 'shape',
|
|
242
|
+
label: t('shape'),
|
|
243
|
+
children: (_jsxs(Form, { size: "small", labelCol: { span: 8 }, wrapperCol: { span: 16 }, children: [_jsx(Form.Item, { label: t('shapeType'), children: _jsx(Select, { value: comp.shapeType || 'rectangle', onChange: (v) => handleChange('shapeType', v), size: "small", style: { width: '100%' }, options: [
|
|
244
|
+
{ value: 'rectangle', label: t('rectangle') },
|
|
245
|
+
{ value: 'ellipse', label: t('ellipse') },
|
|
246
|
+
{ value: 'roundRect', label: t('roundRect') },
|
|
247
|
+
{ value: 'triangle', label: t('triangle') },
|
|
248
|
+
] }) }), _jsx(Form.Item, { label: t('fillColor'), children: _jsx(ColorPicker, { size: "small", value: comp.fillColor || '#ffffff', onChange: (color) => handleChange('fillColor', color.toHexString()), allowClear: true }) }), _jsx(Form.Item, { label: t('shapeBorderColor'), children: _jsx(ColorPicker, { size: "small", value: comp.borderColor || '#000000', onChange: (color) => handleChange('borderColor', color.toHexString()) }) }), _jsx(Form.Item, { label: t('shapeBorderWidth'), children: _jsx(InputNumber, { value: formatUnitValue(comp.borderWidth ?? 0.2, reportUnit), onChange: (v) => handleChange('borderWidth', parseUnitValue(v, reportUnit, comp.borderWidth ?? 0.2)), size: "small", style: { width: '100%' }, min: 0, max: formatUnitValue(5, reportUnit), step: fineUnitStep }) }), _jsx(Form.Item, { label: t('shapeBorderStyle'), children: _jsx(Select, { value: comp.borderStyle || 'solid', onChange: (v) => handleChange('borderStyle', v), size: "small", style: { width: '100%' }, options: [
|
|
249
|
+
{ value: 'solid', label: t('borderSolid') },
|
|
250
|
+
{ value: 'dashed', label: t('borderDashed') },
|
|
251
|
+
{ value: 'dotted', label: t('borderDotted') },
|
|
252
|
+
] }) })] })),
|
|
253
|
+
} : null,
|
|
254
|
+
// ---- 页码 ----
|
|
255
|
+
component.type === 'pagenumber' ? {
|
|
256
|
+
key: 'pagenumber',
|
|
257
|
+
label: t('pageNumber'),
|
|
258
|
+
children: (_jsxs(Form, { size: "small", labelCol: { span: 8 }, wrapperCol: { span: 16 }, children: [_jsx(Form.Item, { label: t('format'), children: _jsx(Select, { value: comp.format || '1/N', onChange: (v) => handleChange('format', v), size: "small", style: { width: '100%' }, options: [
|
|
259
|
+
{ value: '1', label: '1, 2, 3...' },
|
|
260
|
+
{ value: '1/N', label: t('pageNumberFormatFraction') },
|
|
261
|
+
{ value: 'Page 1 of N', label: t('pageNumberFormatPageOf') },
|
|
262
|
+
{ value: 'Page 1', label: t('pageNumberFormatPageOnly') },
|
|
263
|
+
] }) }), _jsx(Form.Item, { label: t('horizontalAlign'), children: _jsx(HorizontalAlignButtons, { value: comp.textAlign || 'center', onChange: (value) => handleChange('textAlign', value), labels: {
|
|
264
|
+
left: t('alignLeft'),
|
|
265
|
+
center: t('alignCenter'),
|
|
266
|
+
right: t('alignRight'),
|
|
267
|
+
} }) }), _jsx(Form.Item, { label: t('verticalAlign'), children: _jsx(VerticalAlignButtons, { value: comp.verticalAlign || 'middle', onChange: (value) => handleChange('verticalAlign', value), labels: {
|
|
268
|
+
top: t('verticalTop'),
|
|
269
|
+
middle: t('verticalMiddle'),
|
|
270
|
+
bottom: t('verticalBottom'),
|
|
271
|
+
} }) })] })),
|
|
272
|
+
} : null,
|
|
273
|
+
// ---- 日期时间 ----
|
|
274
|
+
component.type === 'datetime' ? {
|
|
275
|
+
key: 'datetime',
|
|
276
|
+
label: t('dateTime'),
|
|
277
|
+
children: (_jsxs(Form, { size: "small", labelCol: { span: 8 }, wrapperCol: { span: 16 }, children: [_jsx(Form.Item, { label: t('format'), children: _jsx(Input, { value: comp.format || 'yyyy-MM-dd', onChange: (e) => handleChange('format', e.target.value), size: "small", placeholder: t('dateTimeFormatPlaceholder') }) }), _jsx(Form.Item, { label: t('horizontalAlign'), children: _jsx(HorizontalAlignButtons, { value: comp.textAlign || 'left', onChange: (value) => handleChange('textAlign', value), labels: {
|
|
278
|
+
left: t('alignLeft'),
|
|
279
|
+
center: t('alignCenter'),
|
|
280
|
+
right: t('alignRight'),
|
|
281
|
+
} }) }), _jsx(Form.Item, { label: t('verticalAlign'), children: _jsx(VerticalAlignButtons, { value: comp.verticalAlign || 'middle', onChange: (value) => handleChange('verticalAlign', value), labels: {
|
|
282
|
+
top: t('verticalTop'),
|
|
283
|
+
middle: t('verticalMiddle'),
|
|
284
|
+
bottom: t('verticalBottom'),
|
|
285
|
+
} }) })] })),
|
|
286
|
+
} : null,
|
|
287
|
+
{
|
|
288
|
+
key: 'events',
|
|
289
|
+
label: globalT('events.title'),
|
|
290
|
+
children: (_jsxs(Space, { orientation: "vertical", style: { width: '100%' }, children: [_jsx(Button, { block: true, size: "small", icon: _jsx(EditOutlined, {}), onClick: () => {
|
|
291
|
+
setEventEditorTarget(null);
|
|
292
|
+
setEventEditorOpen(true);
|
|
293
|
+
}, children: globalT('events.edit') }), _jsxs(Typography.Text, { type: "secondary", style: { fontSize: 12 }, children: [Object.keys(comp.events ?? {}).length, " ", globalT('events.title')] })] })),
|
|
294
|
+
},
|
|
295
|
+
].filter(Boolean) }), _jsx(EventEditorDialog, { open: eventEditorOpen, targetType: "component", events: component.events, initialEventName: eventEditorTarget?.eventName, initialCursor: eventEditorTarget ? { line: eventEditorTarget.line, column: eventEditorTarget.column } : undefined, dataContext: buildEventEditorDataContext(template, { targetType: 'component', componentId: component.id }), dictionaryItems: dictionaryItems, componentItems: componentItems, onCancel: () => {
|
|
296
|
+
setEventEditorOpen(false);
|
|
297
|
+
setEventEditorTarget(null);
|
|
298
|
+
}, onSave: (events) => {
|
|
299
|
+
replaceComponentEvents(currentPageId, bandId, component.id, events);
|
|
300
|
+
setEventEditorOpen(false);
|
|
301
|
+
setEventEditorTarget(null);
|
|
302
|
+
} }), _jsx(ExpressionEditor, { open: Boolean(expressionTarget), value: expressionTarget ? String(comp[expressionTarget.field] ?? '') : '', expressionExtensions: expressionExtensions, onChange: (v) => {
|
|
303
|
+
if (expressionTarget)
|
|
304
|
+
handleChange(expressionTarget.field, v);
|
|
305
|
+
}, onClose: () => setExpressionTarget(null) })] }));
|
|
306
|
+
};
|
|
307
|
+
const ComponentContentProperties = ({ component, comp, dataSourceDefinitions, dataSourceOptions, onChange, onChangeMany, onOpenExpressionEditor, t }) => {
|
|
308
|
+
switch (component.type) {
|
|
309
|
+
case 'chart':
|
|
310
|
+
// 图表属性由主组件通过 buildChartPropertyItems 直接展开到外层 Collapse,
|
|
311
|
+
// 不再走 text 包装组,避免折叠面板嵌套。
|
|
312
|
+
return null;
|
|
313
|
+
case 'image': {
|
|
314
|
+
const uploadInputId = `rd-image-upload-${comp.id ?? 'selected'}`;
|
|
315
|
+
const handleImageFileChange = async (event) => {
|
|
316
|
+
const file = event.target.files?.[0];
|
|
317
|
+
if (!file)
|
|
318
|
+
return;
|
|
319
|
+
try {
|
|
320
|
+
const dataUrl = await readImageAsDataUrl(file);
|
|
321
|
+
onChange('src', dataUrl);
|
|
322
|
+
}
|
|
323
|
+
finally {
|
|
324
|
+
event.target.value = '';
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
return (_jsxs(Form, { size: "small", labelCol: { span: 8 }, wrapperCol: { span: 16 }, children: [_jsx(Form.Item, { label: t('imageUrlOrBase64'), children: _jsxs(Space.Compact, { style: { width: '100%' }, children: [_jsx(Input.TextArea, { "aria-label": t('imageUrlOrBase64'), value: comp.src || '', onChange: (event) => onChange('src', event.target.value), size: "small", autoSize: false, rows: 3, placeholder: t('imageUrlOrBase64Placeholder') }), _jsx(ExpressionFieldButton, { label: t('imageUrlOrBase64'), t: t, onClick: () => onOpenExpressionEditor('src', t('imageUrlOrBase64')) })] }) }), _jsxs(Form.Item, { label: t('uploadImage'), children: [_jsx("input", { id: uploadInputId, "aria-label": t('uploadImage'), type: "file", accept: "image/*", style: { position: 'absolute', width: 1, height: 1, opacity: 0, pointerEvents: 'none' }, onChange: handleImageFileChange }), _jsx(Button, { size: "small", icon: _jsx(UploadOutlined, {}), onClick: () => document.getElementById(uploadInputId)?.click(), children: t('uploadImage') })] }), _jsx(Form.Item, { label: t('fitMode'), children: _jsx(Select, { "aria-label": t('fitMode'), value: comp.fitMode || 'contain', onChange: (value) => onChange('fitMode', value), size: "small", virtual: false, options: [
|
|
328
|
+
{ value: 'contain', label: t('fitContain') },
|
|
329
|
+
{ value: 'cover', label: t('fitCover') },
|
|
330
|
+
{ value: 'fill', label: t('fitFill') },
|
|
331
|
+
{ value: 'stretch', label: t('fitStretch') },
|
|
332
|
+
] }) })] }));
|
|
333
|
+
}
|
|
334
|
+
case 'barcode':
|
|
335
|
+
return (_jsxs(Form, { size: "small", labelCol: { span: 8 }, wrapperCol: { span: 16 }, children: [_jsx(Form.Item, { label: t('barcodeContent'), children: _jsxs(Space.Compact, { style: { width: '100%' }, children: [_jsx(Input, { "aria-label": t('barcodeContent'), value: comp.value || '', onChange: (event) => onChange('value', event.target.value), size: "small", placeholder: t('expressionLikePlaceholder') }), _jsx(ExpressionFieldButton, { label: t('barcodeContent'), t: t, onClick: () => onOpenExpressionEditor('value', t('barcodeContent')) })] }) }), _jsx(Form.Item, { label: t('barcodeFormat'), children: _jsx(Select, { "aria-label": t('barcodeFormat'), value: comp.format || 'CODE128', onChange: (value) => onChange('format', value), size: "small", virtual: false, options: BARCODE_FORMATS.map(value => ({ value, label: value })) }) }), _jsx(Form.Item, { label: t('showText'), children: _jsx(Switch, { "aria-label": t('showText'), size: "small", checked: comp.showText ?? true, onChange: (checked) => onChange('showText', checked) }) })] }));
|
|
336
|
+
case 'qrcode':
|
|
337
|
+
return (_jsxs(Form, { size: "small", labelCol: { span: 8 }, wrapperCol: { span: 16 }, children: [_jsx(Form.Item, { label: t('qrcodeContent'), children: _jsxs(Space.Compact, { style: { width: '100%' }, children: [_jsx(Input, { "aria-label": t('qrcodeContent'), value: comp.value || '', onChange: (event) => onChange('value', event.target.value), size: "small", placeholder: t('expressionLikePlaceholder') }), _jsx(ExpressionFieldButton, { label: t('qrcodeContent'), t: t, onClick: () => onOpenExpressionEditor('value', t('qrcodeContent')) })] }) }), _jsx(Form.Item, { label: t('qrcodeFormat'), children: _jsx(Select, { "aria-label": t('qrcodeFormat'), value: comp.format || 'QR_CODE', onChange: (value) => onChange('format', value), size: "small", virtual: false, options: QR_CODE_FORMATS.map(value => ({ value, label: value })) }) })] }));
|
|
338
|
+
case 'checkbox':
|
|
339
|
+
return (_jsxs(Form, { size: "small", labelCol: { span: 8 }, wrapperCol: { span: 16 }, children: [_jsx(Form.Item, { label: t('checkedExpression'), children: _jsxs(Space.Compact, { style: { width: '100%' }, children: [_jsx(Input, { "aria-label": t('checkedExpression'), value: comp.checked || '', onChange: (event) => onChange('checked', event.target.value), size: "small", placeholder: t('expressionLikePlaceholder') }), _jsx(ExpressionFieldButton, { label: t('checkedExpression'), t: t, onClick: () => onOpenExpressionEditor('checked', t('checkedExpression')) })] }) }), _jsx(Form.Item, { label: t('labelText'), children: _jsxs(Space.Compact, { style: { width: '100%' }, children: [_jsx(Input, { "aria-label": t('labelText'), value: comp.label || '', onChange: (event) => onChange('label', event.target.value), size: "small" }), _jsx(ExpressionFieldButton, { label: t('labelText'), t: t, onClick: () => onOpenExpressionEditor('label', t('labelText')) })] }) })] }));
|
|
340
|
+
case 'richtext':
|
|
341
|
+
return (_jsx(Form, { size: "small", labelCol: { span: 8 }, wrapperCol: { span: 16 }, children: _jsx(Form.Item, { label: t('richTextContent'), children: _jsxs(Space.Compact, { style: { width: '100%' }, children: [_jsx(Input.TextArea, { "aria-label": t('richTextContent'), value: comp.html || '', onChange: (event) => onChange('html', event.target.value), autoSize: false, rows: 5, placeholder: "<p>{Data.Field}</p>" }), _jsx(ExpressionFieldButton, { label: t('richTextContent'), t: t, onClick: () => onOpenExpressionEditor('html', t('richTextContent')) })] }) }) }));
|
|
342
|
+
case 'subreport':
|
|
343
|
+
return (_jsxs(Form, { size: "small", labelCol: { span: 8 }, wrapperCol: { span: 16 }, children: [_jsx(Form.Item, { label: t('localTemplateKey'), children: _jsx(Input, { "aria-label": t('localTemplateKey'), value: comp.templateUrl || '', onChange: (event) => onChange('templateUrl', event.target.value), size: "small", placeholder: t('localTemplateKeyPlaceholder') }) }), _jsx(Form.Item, { label: t('parameters'), children: _jsx(Input.TextArea, { "aria-label": t('parameters'), value: JSON.stringify(comp.parameters ?? {}, null, 2), onChange: (event) => {
|
|
344
|
+
try {
|
|
345
|
+
onChange('parameters', JSON.parse(event.target.value || '{}'));
|
|
346
|
+
}
|
|
347
|
+
catch {
|
|
348
|
+
onChange('parameters', comp.parameters ?? {});
|
|
349
|
+
}
|
|
350
|
+
}, autoSize: false, rows: 5 }) })] }));
|
|
351
|
+
case 'panel':
|
|
352
|
+
return _jsx("div", { style: { padding: 8, color: '#999', fontSize: 12 }, children: t('panelContentHint') });
|
|
353
|
+
default:
|
|
354
|
+
return _jsx("div", { style: { padding: 8, color: '#999', fontSize: 12 }, children: t('noContentProperties') });
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
const ExpressionFieldButton = ({ label, onClick, t }) => {
|
|
358
|
+
const title = t('openExpressionEditorFor', { field: label });
|
|
359
|
+
return (_jsx(Button, { "aria-label": title, title: title, icon: _jsx(EditOutlined, {}), onClick: onClick, style: { width: 32 } }));
|
|
360
|
+
};
|
|
361
|
+
function readImageAsDataUrl(file) {
|
|
362
|
+
return new Promise((resolve, reject) => {
|
|
363
|
+
const reader = new FileReader();
|
|
364
|
+
reader.onload = () => resolve(String(reader.result ?? ''));
|
|
365
|
+
reader.onerror = () => reject(reader.error ?? new Error('Failed to read image file'));
|
|
366
|
+
reader.readAsDataURL(file);
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
function findComponentInTree(components, componentId) {
|
|
370
|
+
for (const component of components) {
|
|
371
|
+
if (component.id === componentId)
|
|
372
|
+
return component;
|
|
373
|
+
if ('components' in component && Array.isArray(component.components)) {
|
|
374
|
+
const child = findComponentInTree(component.components ?? [], componentId);
|
|
375
|
+
if (child)
|
|
376
|
+
return child;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return undefined;
|
|
380
|
+
}
|
|
381
|
+
function buildDictionaryEventItems(template) {
|
|
382
|
+
return template.dataSources.map(source => ({
|
|
383
|
+
key: source.id,
|
|
384
|
+
title: source.name || source.id,
|
|
385
|
+
children: (source.schema ?? source.fields ?? []).map(field => ({
|
|
386
|
+
key: `${source.id}.${field.name}`,
|
|
387
|
+
title: field.label || field.name,
|
|
388
|
+
})),
|
|
389
|
+
}));
|
|
390
|
+
}
|
|
391
|
+
function buildComponentEventItems(template) {
|
|
392
|
+
return template.pages.map(page => ({
|
|
393
|
+
key: page.id,
|
|
394
|
+
title: page.id,
|
|
395
|
+
insertable: false,
|
|
396
|
+
children: page.bands.map(band => ({
|
|
397
|
+
key: band.id,
|
|
398
|
+
title: band.name || band.id,
|
|
399
|
+
insertable: false,
|
|
400
|
+
children: buildComponentTreeItems(band.components),
|
|
401
|
+
})),
|
|
402
|
+
}));
|
|
403
|
+
}
|
|
404
|
+
function buildComponentTreeItems(components) {
|
|
405
|
+
return components.flatMap(component => {
|
|
406
|
+
const children = component.type === 'panel'
|
|
407
|
+
? buildComponentTreeItems(component.components ?? [])
|
|
408
|
+
: undefined;
|
|
409
|
+
const item = {
|
|
410
|
+
key: component.id,
|
|
411
|
+
title: component.name ? `${component.name} (${component.type})` : `${component.type}: ${component.id}`,
|
|
412
|
+
name: component.name,
|
|
413
|
+
type: component.type,
|
|
414
|
+
insertable: Boolean(component.name),
|
|
415
|
+
children,
|
|
416
|
+
};
|
|
417
|
+
if (!item.name && !children?.length) {
|
|
418
|
+
return [];
|
|
419
|
+
}
|
|
420
|
+
return [item];
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
function normalizeOptionalBorder(border) {
|
|
424
|
+
if (!border)
|
|
425
|
+
return undefined;
|
|
426
|
+
const hasSide = Boolean(border.sides?.top || border.sides?.right || border.sides?.bottom || border.sides?.left);
|
|
427
|
+
if ((border.style == null || border.style === 'none') && !hasSide) {
|
|
428
|
+
return undefined;
|
|
429
|
+
}
|
|
430
|
+
return border;
|
|
431
|
+
}
|
|
432
|
+
function normalizeOptionalPadding(padding) {
|
|
433
|
+
if (!padding)
|
|
434
|
+
return undefined;
|
|
435
|
+
return padding.top || padding.right || padding.bottom || padding.left ? padding : undefined;
|
|
436
|
+
}
|
|
437
|
+
function propertyBorderLabels(t) {
|
|
438
|
+
return {
|
|
439
|
+
style: t('borderStyle'),
|
|
440
|
+
none: t('borderNone'),
|
|
441
|
+
solid: t('borderSolid'),
|
|
442
|
+
dashed: t('borderDashed'),
|
|
443
|
+
dotted: t('borderDotted'),
|
|
444
|
+
double: t('borderDouble'),
|
|
445
|
+
width: t('borderWidth'),
|
|
446
|
+
color: t('borderColor'),
|
|
447
|
+
sides: t('applySides'),
|
|
448
|
+
sideLabels: {
|
|
449
|
+
top: t('top'),
|
|
450
|
+
right: t('right'),
|
|
451
|
+
bottom: t('bottom'),
|
|
452
|
+
left: t('left'),
|
|
453
|
+
},
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
function propertyPaddingLabels(t) {
|
|
457
|
+
return {
|
|
458
|
+
title: t('padding'),
|
|
459
|
+
top: t('top'),
|
|
460
|
+
right: t('right'),
|
|
461
|
+
bottom: t('bottom'),
|
|
462
|
+
left: t('left'),
|
|
463
|
+
ariaTop: t('paddingTop'),
|
|
464
|
+
ariaRight: t('paddingRight'),
|
|
465
|
+
ariaBottom: t('paddingBottom'),
|
|
466
|
+
ariaLeft: t('paddingLeft'),
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
const propertyEditorMessages = {
|
|
470
|
+
'zh-CN': {
|
|
471
|
+
selectComponent: '选择组件以编辑属性',
|
|
472
|
+
selectedComponents: '已选择 {count} 个组件',
|
|
473
|
+
general: '基本信息',
|
|
474
|
+
position: '位置与尺寸',
|
|
475
|
+
behavior: '行为',
|
|
476
|
+
text: '文本内容',
|
|
477
|
+
font: '字体',
|
|
478
|
+
border: '边框',
|
|
479
|
+
appearance: '外观',
|
|
480
|
+
table: '表格',
|
|
481
|
+
line: '线条属性',
|
|
482
|
+
shape: '形状属性',
|
|
483
|
+
pageNumber: '页码属性',
|
|
484
|
+
dateTime: '日期时间属性',
|
|
485
|
+
chart: '图表属性',
|
|
486
|
+
chartType: '图表类型',
|
|
487
|
+
chartVariant: '图表变种',
|
|
488
|
+
chartBinding: '数据绑定',
|
|
489
|
+
chartDataSource: '数据源',
|
|
490
|
+
chartArrayPath: '数组路径',
|
|
491
|
+
chartArrayPathTooltip: '用于主从报表场景,指定当前行中的子数组字段名(如 Items)。留空则使用数据源顶级数组。',
|
|
492
|
+
chartArrayPathPlaceholder: '如 Items 或 Orders.Lines',
|
|
493
|
+
chartCategoryField: '类目字段',
|
|
494
|
+
chartValueField: '数值字段',
|
|
495
|
+
chartXField: 'X 轴字段',
|
|
496
|
+
chartYField: 'Y 轴字段',
|
|
497
|
+
chartSeriesField: '系列字段',
|
|
498
|
+
chartLabelField: '标签字段',
|
|
499
|
+
chartAggregate: '聚合',
|
|
500
|
+
chartAggregateNone: '不聚合',
|
|
501
|
+
chartAggregateSum: '求和',
|
|
502
|
+
chartAggregateAvg: '平均值',
|
|
503
|
+
chartAggregateCount: '计数',
|
|
504
|
+
chartAggregateMin: '最小值',
|
|
505
|
+
chartAggregateMax: '最大值',
|
|
506
|
+
chartAppearance: '图表外观',
|
|
507
|
+
chartTitle: '图表标题',
|
|
508
|
+
chartSubtitle: '副标题',
|
|
509
|
+
chartShowLegend: '显示图例',
|
|
510
|
+
chartLegendPosition: '图例位置',
|
|
511
|
+
chartShowAxes: '显示坐标轴',
|
|
512
|
+
chartShowGrid: '显示网格',
|
|
513
|
+
chartShowLabels: '显示标签',
|
|
514
|
+
chartAxisTitleX: 'X 轴标题',
|
|
515
|
+
chartAxisTitleY: 'Y 轴标题',
|
|
516
|
+
chartPalette: '调色板',
|
|
517
|
+
chartPalettePlaceholder: '使用逗号分隔,例如 #2f6fed,#16a34a',
|
|
518
|
+
chartEmptyMessage: '空数据提示',
|
|
519
|
+
chartTypeColumn: '柱状图',
|
|
520
|
+
chartTypeColumnParallel: '分组柱状图',
|
|
521
|
+
chartTypeColumnPercent: '百分比柱状图',
|
|
522
|
+
chartTypeBar: '条形图',
|
|
523
|
+
chartTypeBarParallel: '分组条形图',
|
|
524
|
+
chartTypeBarPercent: '百分比条形图',
|
|
525
|
+
chartTypeLine: '折线图',
|
|
526
|
+
chartTypeArea: '面积图',
|
|
527
|
+
chartTypeAreaPercent: '百分比面积图',
|
|
528
|
+
chartTypePie: '饼图',
|
|
529
|
+
chartTypeDonut: '环形图',
|
|
530
|
+
chartTypeRose: '玫瑰图',
|
|
531
|
+
chartTypeScatter: '散点图',
|
|
532
|
+
chartTypeRadar: '雷达图',
|
|
533
|
+
chartTypeFunnel: '漏斗图',
|
|
534
|
+
chartTypeDualAxis: '双轴图',
|
|
535
|
+
chartTypeHeatmap: '热力图',
|
|
536
|
+
chartTypeHistogram: '直方图',
|
|
537
|
+
chartTypeBoxPlot: '箱线图',
|
|
538
|
+
chartTypeTreeMap: '矩形树图',
|
|
539
|
+
chartTypeSunburst: '旭日图',
|
|
540
|
+
chartTypeCirclePacking: '圆形填充图',
|
|
541
|
+
chartLabelType: '标签类型',
|
|
542
|
+
chartLabelTypeName: '名称',
|
|
543
|
+
chartLabelTypeValue: '数值',
|
|
544
|
+
chartLabelTypePercent: '百分比',
|
|
545
|
+
chartLabelTypeNameValue: '名称+数值',
|
|
546
|
+
chartAxisLabelRotation: '轴标签旋转',
|
|
547
|
+
chartTheme: '主题设置',
|
|
548
|
+
chartBaseTheme: '基础主题',
|
|
549
|
+
chartThemeLight: '浅色',
|
|
550
|
+
chartThemeDark: '深色',
|
|
551
|
+
chartMarkStyle: '样式设置',
|
|
552
|
+
chartBarWidth: '柱宽',
|
|
553
|
+
chartCornerRadius: '圆角',
|
|
554
|
+
chartFillOpacity: '填充透明度',
|
|
555
|
+
chartCurveType: '曲线类型',
|
|
556
|
+
chartCurveLinear: '直线',
|
|
557
|
+
chartCurveMonotone: '平滑',
|
|
558
|
+
chartCurveStep: '阶梯',
|
|
559
|
+
chartShowPoint: '显示节点',
|
|
560
|
+
chartPointSize: '节点大小',
|
|
561
|
+
chartInnerRadius: '内径',
|
|
562
|
+
chartOuterRadius: '外径',
|
|
563
|
+
chartRoseType: '玫瑰类型',
|
|
564
|
+
chartRoseRadius: '半径',
|
|
565
|
+
chartRoseArea: '面积',
|
|
566
|
+
chartShowTrendLine: '显示趋势线',
|
|
567
|
+
chartTrendLineType: '趋势线类型',
|
|
568
|
+
chartTrendPolynomial: '多项式',
|
|
569
|
+
chartTrendExponential: '指数',
|
|
570
|
+
chartRadarShape: '雷达形状',
|
|
571
|
+
chartRadarPolygon: '多边形',
|
|
572
|
+
chartRadarCircle: '圆形',
|
|
573
|
+
chartShowRadarArea: '填充雷达区域',
|
|
574
|
+
chartRadarAreaOpacity: '雷达填充透明度',
|
|
575
|
+
chartFunnelDirection: '漏斗方向',
|
|
576
|
+
chartVertical: '垂直',
|
|
577
|
+
chartHorizontal: '水平',
|
|
578
|
+
chartFunnelShape: '漏斗形状',
|
|
579
|
+
chartFunnelTrapezoid: '梯形',
|
|
580
|
+
chartFunnelTriangle: '三角形',
|
|
581
|
+
chartFunnelRect: '矩形',
|
|
582
|
+
chartShowConversionRate: '显示转化率',
|
|
583
|
+
name: '名称',
|
|
584
|
+
type: '类型',
|
|
585
|
+
componentName: '组件名称',
|
|
586
|
+
componentNameDuplicate: '组件名称不能重复',
|
|
587
|
+
componentNameRequired: '组件名称不能为空',
|
|
588
|
+
width: '宽度',
|
|
589
|
+
height: '高度',
|
|
590
|
+
visibleExpression: '可见表达式',
|
|
591
|
+
visibleExpressionPlaceholder: '留空表示始终可见,例如 {Orders.ShowTitle}',
|
|
592
|
+
enabledExpression: '启用表达式',
|
|
593
|
+
enabledExpressionPlaceholder: '留空表示始终启用,例如 {Orders.EnableTitle}',
|
|
594
|
+
printableExpression: '可打印表达式',
|
|
595
|
+
printableExpressionPlaceholder: '留空表示始终打印,例如 {Orders.PrintTitle}',
|
|
596
|
+
textContent: '文本内容',
|
|
597
|
+
textContentPlaceholder: '普通文本或 {DataSource.Field}',
|
|
598
|
+
openExpressionEditor: '打开表达式编辑器',
|
|
599
|
+
openExpressionEditorFor: '打开表达式编辑器:{field}',
|
|
600
|
+
expressionLikePlaceholder: '普通值或 {DataSource.Field}',
|
|
601
|
+
textStyle: '文本样式',
|
|
602
|
+
chooseStyle: '选择样式集',
|
|
603
|
+
unbindStyle: '解除绑定',
|
|
604
|
+
conditionalFormat: '条件格式',
|
|
605
|
+
chooseConditionalFormat: '选择条件格式',
|
|
606
|
+
none: '无',
|
|
607
|
+
manage: '管理',
|
|
608
|
+
horizontalAlign: '水平对齐',
|
|
609
|
+
verticalAlign: '垂直对齐',
|
|
610
|
+
canGrow: '自动增大',
|
|
611
|
+
canShrink: '自动缩小',
|
|
612
|
+
textOnly: '文本组件专属',
|
|
613
|
+
imageContent: '图片内容',
|
|
614
|
+
imageContentPlaceholder: '图片地址或 {DataSource.Field}',
|
|
615
|
+
imageUrlOrBase64: '图片地址/Base64',
|
|
616
|
+
imageUrlOrBase64Placeholder: 'URL、Base64 或 {DataSource.Field}',
|
|
617
|
+
uploadImage: '上传图片',
|
|
618
|
+
fitMode: '适应方式',
|
|
619
|
+
fitContain: '等比包含',
|
|
620
|
+
fitCover: '等比裁切',
|
|
621
|
+
fitFill: '填充',
|
|
622
|
+
fitStretch: '拉伸',
|
|
623
|
+
barcodeContent: '条码内容',
|
|
624
|
+
barcodeFormat: '条码类型',
|
|
625
|
+
qrcodeContent: '二维码内容',
|
|
626
|
+
qrcodeFormat: '二维码类型',
|
|
627
|
+
showText: '显示文本',
|
|
628
|
+
checkedExpression: '选中表达式',
|
|
629
|
+
labelText: '标签文本',
|
|
630
|
+
richTextContent: '富文本内容',
|
|
631
|
+
localTemplateKey: '本地模板键/名称',
|
|
632
|
+
localTemplateKeyPlaceholder: '例如:invoice-detail',
|
|
633
|
+
parameters: '参数',
|
|
634
|
+
panelContentHint: '面板可承载子组件,使用外观和边框属性设置容器样式。',
|
|
635
|
+
noContentProperties: '该组件暂无专属内容属性。',
|
|
636
|
+
fontFamily: '字体系列',
|
|
637
|
+
fontSize: '字号',
|
|
638
|
+
textColor: '字体颜色',
|
|
639
|
+
bold: '加粗',
|
|
640
|
+
italic: '斜体',
|
|
641
|
+
underline: '下划线',
|
|
642
|
+
strike: '删除线',
|
|
643
|
+
borderStyle: '边框样式',
|
|
644
|
+
borderNone: '无边框',
|
|
645
|
+
borderSolid: '实线',
|
|
646
|
+
borderDashed: '虚线',
|
|
647
|
+
borderDotted: '点线',
|
|
648
|
+
borderDouble: '双线',
|
|
649
|
+
borderWidth: '边框宽度',
|
|
650
|
+
borderColor: '边框颜色',
|
|
651
|
+
applySides: '应用边',
|
|
652
|
+
top: '上',
|
|
653
|
+
right: '右',
|
|
654
|
+
bottom: '下',
|
|
655
|
+
left: '左',
|
|
656
|
+
backgroundColor: '背景色',
|
|
657
|
+
foregroundColor: '前景色',
|
|
658
|
+
foregroundColorPicker: '前景色选择器',
|
|
659
|
+
padding: '内边距',
|
|
660
|
+
paddingTop: '内边距上',
|
|
661
|
+
paddingRight: '内边距右',
|
|
662
|
+
paddingBottom: '内边距下',
|
|
663
|
+
paddingLeft: '内边距左',
|
|
664
|
+
tableDataSource: '表格数据源',
|
|
665
|
+
tableBindingMode: '绑定模式',
|
|
666
|
+
tableBindingFixed: '固定',
|
|
667
|
+
tableBindingDetail: '明细',
|
|
668
|
+
tableBindingDataSourceId: '绑定数组属性',
|
|
669
|
+
tableBindingArrayPath: '数组路径',
|
|
670
|
+
tableBindingArrayPathPlaceholder: '例如:Items 或 Customer.Orders',
|
|
671
|
+
dataSource: '数据源',
|
|
672
|
+
chooseDataSource: '选择数据源',
|
|
673
|
+
columnCount: '列数',
|
|
674
|
+
rowCount: '行数',
|
|
675
|
+
rowHeight: '明细行高',
|
|
676
|
+
tableColumns: '列定义',
|
|
677
|
+
tableColumn: '第 {index} 列',
|
|
678
|
+
tableColumnHeader: '标题',
|
|
679
|
+
tableColumnField: '字段',
|
|
680
|
+
tableColumnWidth: '宽度',
|
|
681
|
+
tableColumnType: '类型',
|
|
682
|
+
tableColumnHeaderAria: '第 {index} 列标题',
|
|
683
|
+
tableColumnFieldAria: '第 {index} 列字段',
|
|
684
|
+
tableColumnWidthAria: '第 {index} 列宽度',
|
|
685
|
+
tableColumnTypeAria: '第 {index} 列类型',
|
|
686
|
+
tableCellTypeText: '文本',
|
|
687
|
+
canBreak: '允许跨页',
|
|
688
|
+
showBorder: '显示边框',
|
|
689
|
+
color: '颜色',
|
|
690
|
+
lineWidth: '宽度',
|
|
691
|
+
lineStyle: '样式',
|
|
692
|
+
lineEndpoints: '端点坐标',
|
|
693
|
+
startX: '起点 X',
|
|
694
|
+
startY: '起点 Y',
|
|
695
|
+
endX: '终点 X',
|
|
696
|
+
endY: '终点 Y',
|
|
697
|
+
shapeType: '形状类型',
|
|
698
|
+
rectangle: '矩形',
|
|
699
|
+
ellipse: '椭圆',
|
|
700
|
+
roundRect: '圆角矩形',
|
|
701
|
+
triangle: '三角形',
|
|
702
|
+
fillColor: '填充色',
|
|
703
|
+
shapeBorderColor: '边框色',
|
|
704
|
+
shapeBorderWidth: '边框宽',
|
|
705
|
+
shapeBorderStyle: '边框样式',
|
|
706
|
+
format: '格式',
|
|
707
|
+
pageNumberFormatFraction: '第 1 / N 页',
|
|
708
|
+
pageNumberFormatPageOf: '第 1 页,共 N 页',
|
|
709
|
+
pageNumberFormatPageOnly: '第 1 页',
|
|
710
|
+
dateTimeFormatPlaceholder: 'yyyy-MM-dd HH:mm:ss',
|
|
711
|
+
alignLeft: '左对齐',
|
|
712
|
+
alignCenter: '水平居中',
|
|
713
|
+
alignRight: '右对齐',
|
|
714
|
+
verticalTop: '顶部对齐',
|
|
715
|
+
verticalMiddle: '垂直居中',
|
|
716
|
+
verticalBottom: '底部对齐',
|
|
717
|
+
},
|
|
718
|
+
'en-US': {
|
|
719
|
+
selectComponent: 'Select a component to edit properties',
|
|
720
|
+
selectedComponents: '{count} components selected',
|
|
721
|
+
general: 'General',
|
|
722
|
+
position: 'Position and Size',
|
|
723
|
+
behavior: 'Behavior',
|
|
724
|
+
text: 'Text Content',
|
|
725
|
+
font: 'Font',
|
|
726
|
+
border: 'Border',
|
|
727
|
+
appearance: 'Appearance',
|
|
728
|
+
table: 'Table',
|
|
729
|
+
line: 'Line Properties',
|
|
730
|
+
shape: 'Shape Properties',
|
|
731
|
+
pageNumber: 'Page Number Properties',
|
|
732
|
+
dateTime: 'Date/Time Properties',
|
|
733
|
+
chart: 'Chart Properties',
|
|
734
|
+
chartType: 'Chart type',
|
|
735
|
+
chartVariant: 'Variant',
|
|
736
|
+
chartBinding: 'Data binding',
|
|
737
|
+
chartDataSource: 'Data source',
|
|
738
|
+
chartArrayPath: 'Array path',
|
|
739
|
+
chartArrayPathTooltip: 'For master-detail reports, specifies the sub-array field on the current row (e.g. Items). Leave empty to use the top-level data source array.',
|
|
740
|
+
chartArrayPathPlaceholder: 'e.g. Items or Orders.Lines',
|
|
741
|
+
chartCategoryField: 'Category field',
|
|
742
|
+
chartValueField: 'Value field',
|
|
743
|
+
chartXField: 'X field',
|
|
744
|
+
chartYField: 'Y field',
|
|
745
|
+
chartSeriesField: 'Series field',
|
|
746
|
+
chartLabelField: 'Label field',
|
|
747
|
+
chartAggregate: 'Aggregate',
|
|
748
|
+
chartAggregateNone: 'None',
|
|
749
|
+
chartAggregateSum: 'Sum',
|
|
750
|
+
chartAggregateAvg: 'Average',
|
|
751
|
+
chartAggregateCount: 'Count',
|
|
752
|
+
chartAggregateMin: 'Min',
|
|
753
|
+
chartAggregateMax: 'Max',
|
|
754
|
+
chartAppearance: 'Chart appearance',
|
|
755
|
+
chartTitle: 'Chart title',
|
|
756
|
+
chartSubtitle: 'Subtitle',
|
|
757
|
+
chartShowLegend: 'Show legend',
|
|
758
|
+
chartLegendPosition: 'Legend position',
|
|
759
|
+
chartShowAxes: 'Show axes',
|
|
760
|
+
chartShowGrid: 'Show grid',
|
|
761
|
+
chartShowLabels: 'Show labels',
|
|
762
|
+
chartAxisTitleX: 'X axis title',
|
|
763
|
+
chartAxisTitleY: 'Y axis title',
|
|
764
|
+
chartPalette: 'Palette',
|
|
765
|
+
chartPalettePlaceholder: 'Comma separated, for example #2f6fed,#16a34a',
|
|
766
|
+
chartEmptyMessage: 'Empty message',
|
|
767
|
+
chartTypeColumn: 'Column',
|
|
768
|
+
chartTypeColumnParallel: 'Grouped Column',
|
|
769
|
+
chartTypeColumnPercent: 'Percent Column',
|
|
770
|
+
chartTypeBar: 'Bar',
|
|
771
|
+
chartTypeBarParallel: 'Grouped Bar',
|
|
772
|
+
chartTypeBarPercent: 'Percent Bar',
|
|
773
|
+
chartTypeLine: 'Line',
|
|
774
|
+
chartTypeArea: 'Area',
|
|
775
|
+
chartTypeAreaPercent: 'Percent Area',
|
|
776
|
+
chartTypePie: 'Pie',
|
|
777
|
+
chartTypeDonut: 'Donut',
|
|
778
|
+
chartTypeRose: 'Rose',
|
|
779
|
+
chartTypeScatter: 'Scatter',
|
|
780
|
+
chartTypeRadar: 'Radar',
|
|
781
|
+
chartTypeFunnel: 'Funnel',
|
|
782
|
+
chartTypeDualAxis: 'Dual Axis',
|
|
783
|
+
chartTypeHeatmap: 'Heatmap',
|
|
784
|
+
chartTypeHistogram: 'Histogram',
|
|
785
|
+
chartTypeBoxPlot: 'Box Plot',
|
|
786
|
+
chartTypeTreeMap: 'Tree Map',
|
|
787
|
+
chartTypeSunburst: 'Sunburst',
|
|
788
|
+
chartTypeCirclePacking: 'Circle Packing',
|
|
789
|
+
chartLabelType: 'Label type',
|
|
790
|
+
chartLabelTypeName: 'Name',
|
|
791
|
+
chartLabelTypeValue: 'Value',
|
|
792
|
+
chartLabelTypePercent: 'Percent',
|
|
793
|
+
chartLabelTypeNameValue: 'Name+Value',
|
|
794
|
+
chartAxisLabelRotation: 'Axis label rotation',
|
|
795
|
+
chartTheme: 'Theme',
|
|
796
|
+
chartBaseTheme: 'Base theme',
|
|
797
|
+
chartThemeLight: 'Light',
|
|
798
|
+
chartThemeDark: 'Dark',
|
|
799
|
+
chartMarkStyle: 'Mark Style',
|
|
800
|
+
chartBarWidth: 'Bar width',
|
|
801
|
+
chartCornerRadius: 'Corner radius',
|
|
802
|
+
chartFillOpacity: 'Fill opacity',
|
|
803
|
+
chartCurveType: 'Curve type',
|
|
804
|
+
chartCurveLinear: 'Linear',
|
|
805
|
+
chartCurveMonotone: 'Smooth',
|
|
806
|
+
chartCurveStep: 'Step',
|
|
807
|
+
chartShowPoint: 'Show points',
|
|
808
|
+
chartPointSize: 'Point size',
|
|
809
|
+
chartInnerRadius: 'Inner radius',
|
|
810
|
+
chartOuterRadius: 'Outer radius',
|
|
811
|
+
chartRoseType: 'Rose type',
|
|
812
|
+
chartRoseRadius: 'Radius',
|
|
813
|
+
chartRoseArea: 'Area',
|
|
814
|
+
chartShowTrendLine: 'Show trend line',
|
|
815
|
+
chartTrendLineType: 'Trend line type',
|
|
816
|
+
chartTrendPolynomial: 'Polynomial',
|
|
817
|
+
chartTrendExponential: 'Exponential',
|
|
818
|
+
chartRadarShape: 'Radar shape',
|
|
819
|
+
chartRadarPolygon: 'Polygon',
|
|
820
|
+
chartRadarCircle: 'Circle',
|
|
821
|
+
chartShowRadarArea: 'Fill radar area',
|
|
822
|
+
chartRadarAreaOpacity: 'Radar area opacity',
|
|
823
|
+
chartFunnelDirection: 'Funnel direction',
|
|
824
|
+
chartVertical: 'Vertical',
|
|
825
|
+
chartHorizontal: 'Horizontal',
|
|
826
|
+
chartFunnelShape: 'Funnel shape',
|
|
827
|
+
chartFunnelTrapezoid: 'Trapezoid',
|
|
828
|
+
chartFunnelTriangle: 'Triangle',
|
|
829
|
+
chartFunnelRect: 'Rectangle',
|
|
830
|
+
chartShowConversionRate: 'Show conversion rate',
|
|
831
|
+
name: 'Name',
|
|
832
|
+
type: 'Type',
|
|
833
|
+
componentName: 'Component name',
|
|
834
|
+
componentNameDuplicate: 'Component name must be unique',
|
|
835
|
+
componentNameRequired: 'Component name is required',
|
|
836
|
+
width: 'Width',
|
|
837
|
+
height: 'Height',
|
|
838
|
+
visibleExpression: 'Visible expression',
|
|
839
|
+
visibleExpressionPlaceholder: 'Leave empty to always show, for example {Orders.ShowTitle}',
|
|
840
|
+
enabledExpression: 'Enabled expression',
|
|
841
|
+
enabledExpressionPlaceholder: 'Leave empty to always enable, for example {Orders.EnableTitle}',
|
|
842
|
+
printableExpression: 'Printable expression',
|
|
843
|
+
printableExpressionPlaceholder: 'Leave empty to always print, for example {Orders.PrintTitle}',
|
|
844
|
+
textContent: 'Text content',
|
|
845
|
+
textContentPlaceholder: 'Plain text or {DataSource.Field}',
|
|
846
|
+
openExpressionEditor: 'Open expression editor',
|
|
847
|
+
openExpressionEditorFor: 'Open expression editor: {field}',
|
|
848
|
+
expressionLikePlaceholder: 'Plain value or {DataSource.Field}',
|
|
849
|
+
textStyle: 'Text style',
|
|
850
|
+
chooseStyle: 'Select style',
|
|
851
|
+
unbindStyle: 'Unbind style',
|
|
852
|
+
conditionalFormat: 'Conditional format',
|
|
853
|
+
chooseConditionalFormat: 'Select conditional format',
|
|
854
|
+
none: 'None',
|
|
855
|
+
manage: 'Manage',
|
|
856
|
+
horizontalAlign: 'Horizontal align',
|
|
857
|
+
verticalAlign: 'Vertical align',
|
|
858
|
+
canGrow: 'Can grow',
|
|
859
|
+
canShrink: 'Can shrink',
|
|
860
|
+
textOnly: 'Text components only',
|
|
861
|
+
imageContent: 'Image content',
|
|
862
|
+
imageContentPlaceholder: 'Image URL or {DataSource.Field}',
|
|
863
|
+
imageUrlOrBase64: 'Image URL/Base64',
|
|
864
|
+
imageUrlOrBase64Placeholder: 'URL, Base64, or {DataSource.Field}',
|
|
865
|
+
uploadImage: 'Upload image',
|
|
866
|
+
fitMode: 'Fit mode',
|
|
867
|
+
fitContain: 'Contain',
|
|
868
|
+
fitCover: 'Cover',
|
|
869
|
+
fitFill: 'Fill',
|
|
870
|
+
fitStretch: 'Stretch',
|
|
871
|
+
barcodeContent: 'Barcode content',
|
|
872
|
+
barcodeFormat: 'Barcode type',
|
|
873
|
+
qrcodeContent: 'QR code content',
|
|
874
|
+
qrcodeFormat: 'QR code type',
|
|
875
|
+
showText: 'Show text',
|
|
876
|
+
checkedExpression: 'Checked expression',
|
|
877
|
+
labelText: 'Label text',
|
|
878
|
+
richTextContent: 'Rich Text Content',
|
|
879
|
+
localTemplateKey: 'Local template key/name',
|
|
880
|
+
localTemplateKeyPlaceholder: 'For example: invoice-detail',
|
|
881
|
+
parameters: 'Parameters',
|
|
882
|
+
panelContentHint: 'Panels host child components. Use appearance and border properties for container styling.',
|
|
883
|
+
noContentProperties: 'This component has no content-specific properties.',
|
|
884
|
+
fontFamily: 'Font family',
|
|
885
|
+
fontSize: 'Font size',
|
|
886
|
+
textColor: 'Font color',
|
|
887
|
+
bold: 'Bold',
|
|
888
|
+
italic: 'Italic',
|
|
889
|
+
underline: 'Underline',
|
|
890
|
+
strike: 'Strike',
|
|
891
|
+
borderStyle: 'Border style',
|
|
892
|
+
borderNone: 'None',
|
|
893
|
+
borderSolid: 'Solid',
|
|
894
|
+
borderDashed: 'Dashed',
|
|
895
|
+
borderDotted: 'Dotted',
|
|
896
|
+
borderDouble: 'Double',
|
|
897
|
+
borderWidth: 'Border width',
|
|
898
|
+
borderColor: 'Border color',
|
|
899
|
+
applySides: 'Apply sides',
|
|
900
|
+
top: 'Top',
|
|
901
|
+
right: 'Right',
|
|
902
|
+
bottom: 'Bottom',
|
|
903
|
+
left: 'Left',
|
|
904
|
+
backgroundColor: 'Background color',
|
|
905
|
+
foregroundColor: 'Foreground color',
|
|
906
|
+
foregroundColorPicker: 'Foreground color picker',
|
|
907
|
+
padding: 'Padding',
|
|
908
|
+
paddingTop: 'Padding top',
|
|
909
|
+
paddingRight: 'Padding right',
|
|
910
|
+
paddingBottom: 'Padding bottom',
|
|
911
|
+
paddingLeft: 'Padding left',
|
|
912
|
+
tableDataSource: 'Table data source',
|
|
913
|
+
tableBindingMode: 'Binding mode',
|
|
914
|
+
tableBindingFixed: 'Fixed',
|
|
915
|
+
tableBindingDetail: 'Detail',
|
|
916
|
+
tableBindingDataSourceId: 'Bound array property',
|
|
917
|
+
tableBindingArrayPath: 'Array path',
|
|
918
|
+
tableBindingArrayPathPlaceholder: 'For example: Items or Customer.Orders',
|
|
919
|
+
dataSource: 'Data source',
|
|
920
|
+
chooseDataSource: 'Select data source',
|
|
921
|
+
columnCount: 'Columns',
|
|
922
|
+
rowCount: 'Rows',
|
|
923
|
+
rowHeight: 'Detail row height',
|
|
924
|
+
tableColumns: 'Columns',
|
|
925
|
+
tableColumn: 'Column {index}',
|
|
926
|
+
tableColumnHeader: 'Header',
|
|
927
|
+
tableColumnField: 'Field',
|
|
928
|
+
tableColumnWidth: 'Width',
|
|
929
|
+
tableColumnType: 'Type',
|
|
930
|
+
tableColumnHeaderAria: 'Column {index} header',
|
|
931
|
+
tableColumnFieldAria: 'Column {index} field',
|
|
932
|
+
tableColumnWidthAria: 'Column {index} width',
|
|
933
|
+
tableColumnTypeAria: 'Column {index} type',
|
|
934
|
+
tableCellTypeText: 'Text',
|
|
935
|
+
canBreak: 'Can break',
|
|
936
|
+
showBorder: 'Show border',
|
|
937
|
+
color: 'Color',
|
|
938
|
+
lineWidth: 'Width',
|
|
939
|
+
lineStyle: 'Style',
|
|
940
|
+
lineEndpoints: 'Endpoints',
|
|
941
|
+
startX: 'Start X',
|
|
942
|
+
startY: 'Start Y',
|
|
943
|
+
endX: 'End X',
|
|
944
|
+
endY: 'End Y',
|
|
945
|
+
shapeType: 'Shape type',
|
|
946
|
+
rectangle: 'Rectangle',
|
|
947
|
+
ellipse: 'Ellipse',
|
|
948
|
+
roundRect: 'Round rectangle',
|
|
949
|
+
triangle: 'Triangle',
|
|
950
|
+
fillColor: 'Fill',
|
|
951
|
+
shapeBorderColor: 'Border color',
|
|
952
|
+
shapeBorderWidth: 'Border width',
|
|
953
|
+
shapeBorderStyle: 'Border style',
|
|
954
|
+
format: 'Format',
|
|
955
|
+
pageNumberFormatFraction: '1 / N',
|
|
956
|
+
pageNumberFormatPageOf: 'Page 1 of N',
|
|
957
|
+
pageNumberFormatPageOnly: 'Page 1',
|
|
958
|
+
dateTimeFormatPlaceholder: 'yyyy-MM-dd HH:mm:ss',
|
|
959
|
+
alignLeft: 'Align left',
|
|
960
|
+
alignCenter: 'Center horizontally',
|
|
961
|
+
alignRight: 'Align right',
|
|
962
|
+
verticalTop: 'Align top',
|
|
963
|
+
verticalMiddle: 'Center vertically',
|
|
964
|
+
verticalBottom: 'Align bottom',
|
|
965
|
+
},
|
|
966
|
+
};
|
|
967
|
+
function createPropertyT(locale) {
|
|
968
|
+
const messages = propertyEditorMessages[locale] ?? propertyEditorMessages['zh-CN'];
|
|
969
|
+
const fallback = propertyEditorMessages['en-US'];
|
|
970
|
+
return (key, values) => {
|
|
971
|
+
const message = messages[key] ?? fallback[key] ?? key;
|
|
972
|
+
if (!values)
|
|
973
|
+
return message;
|
|
974
|
+
return message.replace(/\{(\w+)\}/g, (match, valueKey) => (Object.prototype.hasOwnProperty.call(values, valueKey) ? String(values[valueKey]) : match));
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
const HorizontalAlignButtons = ({ disabled = false, labels, onChange, value }) => (_jsx(IconButtonGroup, { items: [
|
|
978
|
+
{ value: 'left', label: labels?.left ?? '左对齐', icon: _jsx(AlignLeftOutlined, {}) },
|
|
979
|
+
{ value: 'center', label: labels?.center ?? '水平居中', icon: _jsx(AlignCenterOutlined, {}) },
|
|
980
|
+
{ value: 'right', label: labels?.right ?? '右对齐', icon: _jsx(AlignRightOutlined, {}) },
|
|
981
|
+
], value: value, onChange: onChange, disabled: disabled }));
|
|
982
|
+
const VerticalAlignButtons = ({ disabled = false, labels, onChange, value }) => (_jsx(IconButtonGroup, { items: [
|
|
983
|
+
{ value: 'top', label: labels?.top ?? '顶部对齐', icon: _jsx(VerticalAlignGlyph, { position: "top" }) },
|
|
984
|
+
{ value: 'middle', label: labels?.middle ?? '垂直居中', icon: _jsx(VerticalAlignGlyph, { position: "middle" }) },
|
|
985
|
+
{ value: 'bottom', label: labels?.bottom ?? '底部对齐', icon: _jsx(VerticalAlignGlyph, { position: "bottom" }) },
|
|
986
|
+
], value: value, onChange: onChange, disabled: disabled }));
|
|
987
|
+
const IconButtonGroup = ({ disabled, items, onChange, value, }) => (_jsx(Space, { size: 4, wrap: true, children: items.map(item => (_jsx(Button, { "aria-label": item.label, title: item.label, size: "small", type: value === item.value ? 'primary' : 'default', icon: item.icon, disabled: disabled, onClick: () => onChange(item.value), style: { width: 28, paddingInline: 0 } }, item.value))) }));
|
|
988
|
+
const VerticalAlignGlyph = ({ position }) => {
|
|
989
|
+
const blockTop = position === 'top' ? 2 : position === 'middle' ? 8 : 14;
|
|
990
|
+
return (_jsxs("span", { "aria-hidden": "true", style: {
|
|
991
|
+
position: 'relative',
|
|
992
|
+
display: 'inline-block',
|
|
993
|
+
width: 14,
|
|
994
|
+
height: 18,
|
|
995
|
+
}, children: [_jsx("span", { style: { position: 'absolute', left: 0, right: 0, top: 0, height: 1.5, background: 'currentColor', opacity: 0.45, borderRadius: 999 } }), _jsx("span", { style: { position: 'absolute', left: 0, right: 0, top: 8, height: 1.5, background: 'currentColor', opacity: 0.45, borderRadius: 999 } }), _jsx("span", { style: { position: 'absolute', left: 0, right: 0, top: 16, height: 1.5, background: 'currentColor', opacity: 0.45, borderRadius: 999 } }), _jsx("span", { style: { position: 'absolute', left: 2, right: 2, top: blockTop, height: 3.5, background: 'currentColor', borderRadius: 999 } })] }));
|
|
996
|
+
};
|
|
997
|
+
const TablePropertyPanel = ({ table, onChange, t }) => {
|
|
998
|
+
const rowCount = table.rows?.length ?? table.rowCount ?? 1;
|
|
999
|
+
const columnCount = table.rows?.[0]?.cells.length ?? table.columnCount ?? 1;
|
|
1000
|
+
return (_jsx(Space, { orientation: "vertical", size: 12, style: { width: '100%' }, children: _jsxs(Form, { layout: "horizontal", size: "small", labelCol: { span: 8 }, wrapperCol: { span: 16 }, children: [_jsx(Form.Item, { label: t('columnCount'), children: _jsx(InputNumber, { "aria-label": t('columnCount'), value: columnCount, onChange: (value) => onChange({ columnCount: value ?? 1 }), size: "small", style: { width: '100%' }, min: 1, step: 1 }) }), _jsx(Form.Item, { label: t('rowCount'), children: _jsx(InputNumber, { "aria-label": t('rowCount'), value: rowCount, onChange: (value) => onChange({ rowCount: value ?? 1 }), size: "small", style: { width: '100%' }, min: 1, step: 1 }) }), _jsx(Form.Item, { label: t('canBreak'), children: _jsx(Switch, { "aria-label": t('canBreak'), size: "small", checked: table.canBreak ?? true, onChange: (checked) => onChange({ canBreak: checked }) }) })] }) }));
|
|
1001
|
+
};
|
|
1002
|
+
//# sourceMappingURL=PropertyEditor.js.map
|