@nocobase/plugin-charts 0.9.1-alpha.2
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/client.d.ts +4 -0
- package/client.js +30 -0
- package/lib/client/ChartBlockEngine.d.ts +27 -0
- package/lib/client/ChartBlockEngine.js +201 -0
- package/lib/client/ChartBlockEngineDesigner.d.ts +3 -0
- package/lib/client/ChartBlockEngineDesigner.js +348 -0
- package/lib/client/ChartBlockInitializer.d.ts +3 -0
- package/lib/client/ChartBlockInitializer.js +324 -0
- package/lib/client/ChartQueryBlockInitializer.d.ts +9 -0
- package/lib/client/ChartQueryBlockInitializer.js +230 -0
- package/lib/client/ChartQueryMetadataProvider.d.ts +10 -0
- package/lib/client/ChartQueryMetadataProvider.js +118 -0
- package/lib/client/DataSetPreviewTable.d.ts +5 -0
- package/lib/client/DataSetPreviewTable.js +127 -0
- package/lib/client/Icons.d.ts +1 -0
- package/lib/client/Icons.js +226 -0
- package/lib/client/chartRenderComponents/index.d.ts +2 -0
- package/lib/client/chartRenderComponents/index.js +26 -0
- package/lib/client/hooks/index.d.ts +4 -0
- package/lib/client/hooks/index.js +52 -0
- package/lib/client/index.d.ts +4 -0
- package/lib/client/index.js +161 -0
- package/lib/client/locale/en-US.d.ts +23 -0
- package/lib/client/locale/en-US.js +29 -0
- package/lib/client/locale/index.d.ts +3 -0
- package/lib/client/locale/index.js +46 -0
- package/lib/client/locale/ja-JP.d.ts +2 -0
- package/lib/client/locale/ja-JP.js +8 -0
- package/lib/client/locale/ru-RU.d.ts +2 -0
- package/lib/client/locale/ru-RU.js +8 -0
- package/lib/client/locale/tr-TR.d.ts +2 -0
- package/lib/client/locale/tr-TR.js +8 -0
- package/lib/client/locale/zh-CN.d.ts +61 -0
- package/lib/client/locale/zh-CN.js +67 -0
- package/lib/client/select/CustomSelect.d.ts +11 -0
- package/lib/client/select/CustomSelect.js +193 -0
- package/lib/client/select/ReadPretty.d.ts +2 -0
- package/lib/client/select/ReadPretty.js +102 -0
- package/lib/client/select/index.d.ts +2 -0
- package/lib/client/select/index.js +31 -0
- package/lib/client/select/shared.d.ts +7 -0
- package/lib/client/select/shared.js +86 -0
- package/lib/client/settings/AddNewQuery.d.ts +2 -0
- package/lib/client/settings/AddNewQuery.js +321 -0
- package/lib/client/settings/ConfigureFields.d.ts +1 -0
- package/lib/client/settings/ConfigureFields.js +51 -0
- package/lib/client/settings/QueriesTable.d.ts +1 -0
- package/lib/client/settings/QueriesTable.js +108 -0
- package/lib/client/settings/queryTypes.d.ts +5 -0
- package/lib/client/settings/queryTypes.js +85 -0
- package/lib/client/settings/schemas/chartsQueries.d.ts +8 -0
- package/lib/client/settings/schemas/chartsQueries.js +378 -0
- package/lib/client/templates/AreaTemplate.d.ts +65 -0
- package/lib/client/templates/AreaTemplate.js +86 -0
- package/lib/client/templates/BarTemplate.d.ts +80 -0
- package/lib/client/templates/BarTemplate.js +103 -0
- package/lib/client/templates/ColumnTemplate.d.ts +80 -0
- package/lib/client/templates/ColumnTemplate.js +103 -0
- package/lib/client/templates/FunnelTemplate.d.ts +66 -0
- package/lib/client/templates/FunnelTemplate.js +87 -0
- package/lib/client/templates/LineTemplate.d.ts +67 -0
- package/lib/client/templates/LineTemplate.js +92 -0
- package/lib/client/templates/PieTemplate.d.ts +71 -0
- package/lib/client/templates/PieTemplate.js +92 -0
- package/lib/client/templates/RadarTemplate.d.ts +71 -0
- package/lib/client/templates/RadarTemplate.js +93 -0
- package/lib/client/templates/ScatterTemplate.d.ts +91 -0
- package/lib/client/templates/ScatterTemplate.js +112 -0
- package/lib/client/templates/TableTemplate.d.ts +28 -0
- package/lib/client/templates/TableTemplate.js +54 -0
- package/lib/client/templates/index.d.ts +1 -0
- package/lib/client/templates/index.js +33 -0
- package/lib/client/utils.d.ts +3 -0
- package/lib/client/utils.js +66 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +15 -0
- package/lib/server/actions/chartsQueries.d.ts +3 -0
- package/lib/server/actions/chartsQueries.js +104 -0
- package/lib/server/actions/index.d.ts +1 -0
- package/lib/server/actions/index.js +1 -0
- package/lib/server/collections/chartsQueries.d.ts +2 -0
- package/lib/server/collections/chartsQueries.js +36 -0
- package/lib/server/index.d.ts +1 -0
- package/lib/server/index.js +15 -0
- package/lib/server/plugin.d.ts +14 -0
- package/lib/server/plugin.js +142 -0
- package/lib/server/query.d.ts +12 -0
- package/lib/server/query.js +91 -0
- package/lib/server/shared/index.d.ts +2 -0
- package/lib/server/shared/index.js +8 -0
- package/package.json +14 -0
- package/server.d.ts +4 -0
- package/server.js +30 -0
- package/src/client/ChartBlockEngine.tsx +120 -0
- package/src/client/ChartBlockEngineDesigner.tsx +238 -0
- package/src/client/ChartBlockInitializer.tsx +216 -0
- package/src/client/ChartQueryBlockInitializer.tsx +136 -0
- package/src/client/ChartQueryMetadataProvider.tsx +62 -0
- package/src/client/DataSetPreviewTable.tsx +73 -0
- package/src/client/Icons.tsx +99 -0
- package/src/client/chartRenderComponents/index.ts +7 -0
- package/src/client/hooks/index.ts +19 -0
- package/src/client/index.tsx +101 -0
- package/src/client/locale/en-US.ts +23 -0
- package/src/client/locale/index.ts +18 -0
- package/src/client/locale/ja-JP.ts +1 -0
- package/src/client/locale/ru-RU.ts +1 -0
- package/src/client/locale/tr-TR.ts +1 -0
- package/src/client/locale/zh-CN.ts +63 -0
- package/src/client/select/CustomSelect.tsx +127 -0
- package/src/client/select/ReadPretty.tsx +36 -0
- package/src/client/select/index.md +38 -0
- package/src/client/select/index.ts +2 -0
- package/src/client/select/shared.ts +36 -0
- package/src/client/settings/AddNewQuery.tsx +161 -0
- package/src/client/settings/ConfigureFields.tsx +18 -0
- package/src/client/settings/QueriesTable.tsx +26 -0
- package/src/client/settings/queryTypes.ts +64 -0
- package/src/client/settings/schemas/chartsQueries.ts +319 -0
- package/src/client/templates/AreaTemplate.tsx +64 -0
- package/src/client/templates/BarTemplate.tsx +80 -0
- package/src/client/templates/ColumnTemplate.tsx +81 -0
- package/src/client/templates/FunnelTemplate.tsx +65 -0
- package/src/client/templates/LineTemplate.tsx +72 -0
- package/src/client/templates/PieTemplate.tsx +68 -0
- package/src/client/templates/RadarTemplate.tsx +71 -0
- package/src/client/templates/ScatterTemplate.tsx +90 -0
- package/src/client/templates/TableTemplate.tsx +48 -0
- package/src/client/templates/index.ts +21 -0
- package/src/client/utils.ts +39 -0
- package/src/index.ts +1 -0
- package/src/server/actions/chartsQueries.ts +44 -0
- package/src/server/actions/index.ts +0 -0
- package/src/server/collections/.gitkeep +0 -0
- package/src/server/collections/chartsQueries.ts +24 -0
- package/src/server/index.ts +1 -0
- package/src/server/plugin.ts +61 -0
- package/src/server/query.ts +39 -0
- package/src/server/shared/index.ts +2 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { TableOutlined } from '@ant-design/icons';
|
|
2
|
+
import { FormDialog, FormLayout } from '@formily/antd';
|
|
3
|
+
import { SchemaOptionsContext } from '@formily/react';
|
|
4
|
+
import {
|
|
5
|
+
SchemaComponent,
|
|
6
|
+
SchemaComponentOptions,
|
|
7
|
+
SchemaInitializer,
|
|
8
|
+
SchemaInitializerButtonContext,
|
|
9
|
+
useAPIClient,
|
|
10
|
+
} from '@nocobase/client';
|
|
11
|
+
import React, { useContext, useEffect, useState } from 'react';
|
|
12
|
+
import { useChartQueryMetadataContext } from './ChartQueryMetadataProvider';
|
|
13
|
+
import { lang } from './locale';
|
|
14
|
+
import { getQueryTypeSchema } from './settings/queryTypes';
|
|
15
|
+
|
|
16
|
+
export interface ChartQueryMetadata {
|
|
17
|
+
id: number;
|
|
18
|
+
title: string;
|
|
19
|
+
type: string;
|
|
20
|
+
fields: { name: string }[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const ChartQueryBlockInitializer = (props) => {
|
|
24
|
+
const defaultItems: any = [
|
|
25
|
+
{
|
|
26
|
+
type: 'itemGroup',
|
|
27
|
+
title: lang('Select query data'),
|
|
28
|
+
children: [],
|
|
29
|
+
},
|
|
30
|
+
];
|
|
31
|
+
const { templateWrap, onCreateBlockSchema, componentType, createBlockSchema, insert, ...others } = props;
|
|
32
|
+
const { setVisible } = useContext(SchemaInitializerButtonContext);
|
|
33
|
+
const [items, setItems] = useState(defaultItems);
|
|
34
|
+
const apiClient = useAPIClient();
|
|
35
|
+
const ctx = useChartQueryMetadataContext();
|
|
36
|
+
const options = useContext(SchemaOptionsContext);
|
|
37
|
+
const onAddQuery = (info) => {
|
|
38
|
+
FormDialog(
|
|
39
|
+
{
|
|
40
|
+
sql: lang('Add SQL query'),
|
|
41
|
+
json: lang('Add JSON query'),
|
|
42
|
+
}[info.key],
|
|
43
|
+
() => {
|
|
44
|
+
return (
|
|
45
|
+
<div>
|
|
46
|
+
<SchemaComponentOptions scope={options.scope} components={{ ...options.components }}>
|
|
47
|
+
<FormLayout layout={'vertical'}>
|
|
48
|
+
<SchemaComponent
|
|
49
|
+
schema={{
|
|
50
|
+
type: 'object',
|
|
51
|
+
properties: {
|
|
52
|
+
title: {
|
|
53
|
+
title: lang('Title'),
|
|
54
|
+
required: true,
|
|
55
|
+
'x-component': 'Input',
|
|
56
|
+
'x-decorator': 'FormItem',
|
|
57
|
+
},
|
|
58
|
+
options: getQueryTypeSchema(info.key),
|
|
59
|
+
},
|
|
60
|
+
}}
|
|
61
|
+
/>
|
|
62
|
+
</FormLayout>
|
|
63
|
+
</SchemaComponentOptions>
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
66
|
+
},
|
|
67
|
+
)
|
|
68
|
+
.open({
|
|
69
|
+
initialValues: {
|
|
70
|
+
type: info.key,
|
|
71
|
+
},
|
|
72
|
+
})
|
|
73
|
+
.then(async (values) => {
|
|
74
|
+
try {
|
|
75
|
+
const { data } = await apiClient.resource('chartsQueries')?.create?.({ values });
|
|
76
|
+
const items = (await ctx.refresh()) as any;
|
|
77
|
+
const item = items.find((item) => item.id === data?.data?.id);
|
|
78
|
+
onCreateBlockSchema({ item });
|
|
79
|
+
setVisible(false);
|
|
80
|
+
} catch (error) {}
|
|
81
|
+
})
|
|
82
|
+
.catch(() => {});
|
|
83
|
+
};
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
const chartQueryMetadata = ctx.data;
|
|
86
|
+
if (chartQueryMetadata && Array.isArray(chartQueryMetadata)) {
|
|
87
|
+
setItems(
|
|
88
|
+
[
|
|
89
|
+
chartQueryMetadata.length > 0
|
|
90
|
+
? {
|
|
91
|
+
type: 'itemGroup',
|
|
92
|
+
title: '{{t("Select chart query", {ns: "charts"})}}',
|
|
93
|
+
children: chartQueryMetadata,
|
|
94
|
+
}
|
|
95
|
+
: null,
|
|
96
|
+
chartQueryMetadata.length > 0
|
|
97
|
+
? {
|
|
98
|
+
type: 'divider',
|
|
99
|
+
}
|
|
100
|
+
: null,
|
|
101
|
+
,
|
|
102
|
+
{
|
|
103
|
+
type: 'subMenu',
|
|
104
|
+
title: lang('Add chart query'),
|
|
105
|
+
// component: AddChartQuery,
|
|
106
|
+
children: [
|
|
107
|
+
{
|
|
108
|
+
key: 'sql',
|
|
109
|
+
type: 'item',
|
|
110
|
+
title: 'SQL',
|
|
111
|
+
onClick: onAddQuery,
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
key: 'json',
|
|
115
|
+
type: 'item',
|
|
116
|
+
title: 'JSON',
|
|
117
|
+
onClick: onAddQuery,
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
},
|
|
121
|
+
].filter(Boolean),
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
}, []);
|
|
125
|
+
return (
|
|
126
|
+
<SchemaInitializer.Item
|
|
127
|
+
icon={<TableOutlined />}
|
|
128
|
+
{...others}
|
|
129
|
+
onClick={async ({ item }) => {
|
|
130
|
+
onCreateBlockSchema({ item });
|
|
131
|
+
setVisible(false);
|
|
132
|
+
}}
|
|
133
|
+
items={items}
|
|
134
|
+
/>
|
|
135
|
+
);
|
|
136
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { useAPIClient, useRequest } from '@nocobase/client';
|
|
2
|
+
import { Spin } from 'antd';
|
|
3
|
+
import React, { createContext, useContext, useEffect } from 'react';
|
|
4
|
+
import { useLocation } from 'react-router-dom';
|
|
5
|
+
|
|
6
|
+
export const ChartQueryMetadataContext = createContext({
|
|
7
|
+
refresh: () => {},
|
|
8
|
+
data: [] as any[],
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
export const ChartQueryMetadataProvider: React.FC = (props) => {
|
|
12
|
+
const api = useAPIClient();
|
|
13
|
+
|
|
14
|
+
const options = {
|
|
15
|
+
resource: 'chartsQueries',
|
|
16
|
+
action: 'listMetadata',
|
|
17
|
+
params: {
|
|
18
|
+
paginate: false,
|
|
19
|
+
sort: ['-id'],
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const location = useLocation();
|
|
24
|
+
|
|
25
|
+
const service = useRequest(options, {
|
|
26
|
+
manual: true,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const isAdminPage = location.pathname.startsWith('/admin');
|
|
30
|
+
const token = api.auth.getToken() || '';
|
|
31
|
+
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
if (isAdminPage && token) {
|
|
34
|
+
service.run();
|
|
35
|
+
}
|
|
36
|
+
}, [isAdminPage, token]);
|
|
37
|
+
|
|
38
|
+
const refresh = async () => {
|
|
39
|
+
const { data } = await api.request(options);
|
|
40
|
+
service.mutate(data);
|
|
41
|
+
return data?.data || [];
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
if (service.loading) {
|
|
45
|
+
return <Spin />;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<ChartQueryMetadataContext.Provider
|
|
50
|
+
value={{
|
|
51
|
+
refresh,
|
|
52
|
+
data: service.data?.data,
|
|
53
|
+
}}
|
|
54
|
+
>
|
|
55
|
+
{props.children}
|
|
56
|
+
</ChartQueryMetadataContext.Provider>
|
|
57
|
+
);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const useChartQueryMetadataContext = () => {
|
|
61
|
+
return useContext(ChartQueryMetadataContext);
|
|
62
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { ISchema } from '@formily/react';
|
|
2
|
+
import {
|
|
3
|
+
BlockSchemaComponentProvider,
|
|
4
|
+
FormItem,
|
|
5
|
+
Input,
|
|
6
|
+
SchemaComponent,
|
|
7
|
+
SchemaComponentProvider,
|
|
8
|
+
TableV2,
|
|
9
|
+
} from '@nocobase/client';
|
|
10
|
+
import { Empty, Spin } from 'antd';
|
|
11
|
+
import React from 'react';
|
|
12
|
+
import { useGetDataSet } from './ChartBlockEngine';
|
|
13
|
+
|
|
14
|
+
export default ({ queryId, fields }: { queryId: number; fields }) => {
|
|
15
|
+
const { dataSet, loading, error } = useGetDataSet(queryId);
|
|
16
|
+
const columns = {};
|
|
17
|
+
if (fields) {
|
|
18
|
+
for (const field of fields) {
|
|
19
|
+
columns[field.name] = {
|
|
20
|
+
type: 'void',
|
|
21
|
+
title: field.name,
|
|
22
|
+
'x-component': 'TableV2.Column',
|
|
23
|
+
'x-component-props': {
|
|
24
|
+
// width: 200,
|
|
25
|
+
},
|
|
26
|
+
properties: {
|
|
27
|
+
[field.name]: {
|
|
28
|
+
type: 'string',
|
|
29
|
+
'x-component': 'Input',
|
|
30
|
+
'x-read-pretty': true,
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const schema: ISchema = {
|
|
37
|
+
type: 'void',
|
|
38
|
+
properties: {
|
|
39
|
+
input: {
|
|
40
|
+
type: 'array',
|
|
41
|
+
'x-component': 'TableV2',
|
|
42
|
+
'x-component-props': {
|
|
43
|
+
rowKey: 'id',
|
|
44
|
+
scroll: { y: 300 },
|
|
45
|
+
},
|
|
46
|
+
default: dataSet,
|
|
47
|
+
properties: columns,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
if (error) {
|
|
53
|
+
return (
|
|
54
|
+
<>
|
|
55
|
+
<Empty description={<span>May be this chart block's query data has been deleted,please check!</span>} />
|
|
56
|
+
</>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (loading)
|
|
61
|
+
return (
|
|
62
|
+
<>
|
|
63
|
+
<Spin />
|
|
64
|
+
</>
|
|
65
|
+
);
|
|
66
|
+
return (
|
|
67
|
+
<SchemaComponentProvider scope={{ dataSet }} components={{ TableV2, Input, FormItem }}>
|
|
68
|
+
<BlockSchemaComponentProvider>
|
|
69
|
+
<SchemaComponent schema={schema} />
|
|
70
|
+
</BlockSchemaComponentProvider>
|
|
71
|
+
</SchemaComponentProvider>
|
|
72
|
+
);
|
|
73
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Icon } from '@nocobase/client';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
const RadarChart = () => (
|
|
5
|
+
<svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" viewBox="0 0 1024 1024">
|
|
6
|
+
<path d="M523 573.5c-3.9 0.7-7.9 1.1-12 1.1-5.3 0-10.4-0.6-15.2-1.8l-62.2 189.7 167.4-76L523 573.5z"></path>
|
|
7
|
+
<path d="M398.3 767.3l68.9-210.1c-6.4-6-11.5-13.3-15-21.4l-192.6 52.7L398.3 767.3z"></path>
|
|
8
|
+
<path d="M528 448.9c4.1 1.1 8 2.6 11.7 4.5l72.5-61.8L528 263.7 528 448.9z"></path>
|
|
9
|
+
<path d="M259.6 555.4 447.3 504c0.4-4.2 1.3-8.3 2.5-12.2L270.9 373.4 259.6 555.4z"></path>
|
|
10
|
+
<path d="M655.5 396.7l208.3 185.7 30.2 4.8c4.8-24.6 7.4-49.9 7.4-75.9 0-95.9-34.6-183.7-92-251.6L655.5 396.7z"></path>
|
|
11
|
+
<path d="M794.4 563.4 630.9 417.7l-67 57.1c5.6 8.3 9.3 18 10.6 28.4L794.4 563.4z"></path>
|
|
12
|
+
<path d="M496 448.4 496 239.6l-218.8 99.6 189.4 125.4C474.7 456.8 484.8 451.1 496 448.4z"></path>
|
|
13
|
+
<path d="M619.3 713.3 420 803.8l-19.1 81.6c35 10.3 72.1 15.9 110.4 15.9 74.4 0 143.9-20.8 203-56.9L619.3 713.3z"></path>
|
|
14
|
+
<path d="M648.7 699.5l92.3 127.2c63.3-46.2 112.2-111 138.6-186.4L648.7 699.5z"></path>
|
|
15
|
+
<path d="M386.2 804 226.1 597.7l-87.9 27.4c34.9 114.7 121.3 207 232.2 250L386.2 804z"></path>
|
|
16
|
+
<path d="M226.9 564.3 240.2 353l-64.4-40.5c-34.6 58.2-54.4 126.2-54.4 198.8 0 28.4 3 56.2 8.8 82.9L226.9 564.3z"></path>
|
|
17
|
+
<path d="M842.8 609.8l-272.7-74.7c-4 9.5-10.1 17.9-17.9 24.4l77.3 112.1L842.8 609.8z"></path>
|
|
18
|
+
<path d="M528 205.4l108.8 165.2 151-134.5c-67-67.3-158.4-110.2-259.7-114.5L528.1 205.4z"></path>
|
|
19
|
+
<path d="M245.7 318.4l250.3-114 0-82.8c-125 4.8-234.8 68.5-302.8 164L245.7 318.4z"></path>
|
|
20
|
+
</svg>
|
|
21
|
+
);
|
|
22
|
+
const FunnelChart = () => (
|
|
23
|
+
<svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" viewBox="0 0 1024 1024">
|
|
24
|
+
<path d="M533.6 784.5c6.6 16.4-1.3 35-17.6 41.7l0 0c-16.4 6.6-35-1.3-41.7-17.6L129.9 236c-6.6-16.4 1.3-35 17.6-41.7l0 0c16.4-6.6 35 1.3 41.7 17.6L533.6 784.5z"></path>
|
|
25
|
+
<path d="M536 812.2c-6.9 16.3-25.7 23.9-41.9 17l0 0c-16.3-6.9-23.9-25.7-17-41.9l357.6-575.7c6.9-16.3 25.7-23.9 41.9-17l0 0c16.3 6.9 23.9 25.7 17 41.9L536 812.2z"></path>
|
|
26
|
+
<path d="M895.4 224c0 17.7-14.3 32-32 32l-704 0c-17.7 0-32-14.3-32-32l0 0c0-17.7 14.3-32 32-32l704 0C881 192 895.4 206.3 895.4 224L895.4 224z"></path>
|
|
27
|
+
<path d="M278.6 384l465 0 0 64-465 0 0-64Z"></path>
|
|
28
|
+
<path d="M391.6 576l232.5 0 0 64-232.5 0 0-64Z"></path>
|
|
29
|
+
</svg>
|
|
30
|
+
);
|
|
31
|
+
const ScatterChart = () => (
|
|
32
|
+
<svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" viewBox="0 0 1024 1024">
|
|
33
|
+
<path d="M191 864c0 17.7-14.3 32-32 32l0 0c-17.7 0-32-14.3-32-32L127 160c0-17.7 14.3-32 32-32l0 0c17.7 0 32 14.3 32 32L191 864z"></path>
|
|
34
|
+
<path d="M159 896c-17.7 0-32-14.3-32-32l0 0c0-17.7 14.3-32 32-32l712 0c17.7 0 32 14.3 32 32l0 0c0 17.7-14.3 32-32 32L159 896z"></path>
|
|
35
|
+
<path d="M745.6 765.9"></path>
|
|
36
|
+
<path d="M307.6 244.3m-48 0a48 48 0 1 0 96 0 48 48 0 1 0-96 0Z"></path>
|
|
37
|
+
<path d="M560 479.2m-48 0a48 48 0 1 0 96 0 48 48 0 1 0-96 0Z"></path>
|
|
38
|
+
<path d="M391.9 387.7m-48 0a48 48 0 1 0 96 0 48 48 0 1 0-96 0Z"></path>
|
|
39
|
+
<path d="M540.4 244.3m-48 0a48 48 0 1 0 96 0 48 48 0 1 0-96 0Z"></path>
|
|
40
|
+
<path d="M732.9 292.3m-48 0a48 48 0 1 0 96 0 48 48 0 1 0-96 0Z"></path>
|
|
41
|
+
<path d="M792.9 717.9m-48 0a48 48 0 1 0 96 0 48 48 0 1 0-96 0Z"></path>
|
|
42
|
+
<path d="M307.6 527.2m-48 0a48 48 0 1 0 96 0 48 48 0 1 0-96 0Z"></path>
|
|
43
|
+
<path d="M439.9 662.4m-48 0a48 48 0 1 0 96 0 48 48 0 1 0-96 0Z"></path>
|
|
44
|
+
</svg>
|
|
45
|
+
);
|
|
46
|
+
const ColumnChart = () => (
|
|
47
|
+
<svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" viewBox="0 0 1024 1024">
|
|
48
|
+
<path d="M191 864c0 17.7-14.3 32-32 32l0 0c-17.7 0-32-14.3-32-32L127 160c0-17.7 14.3-32 32-32l0 0c17.7 0 32 14.3 32 32L191 864z"></path>
|
|
49
|
+
<path d="M159 896c-17.7 0-32-14.3-32-32l0 0c0-17.7 14.3-32 32-32l712 0c17.7 0 32 14.3 32 32l0 0c0 17.7-14.3 32-32 32L159 896z"></path>
|
|
50
|
+
<path d="M745.6 765.9"></path>
|
|
51
|
+
<path d="M342.1 734.3c0 17.5-14.2 31.7-31.7 31.7l0 0c-17.5 0-31.7-14.2-31.7-31.7L278.7 489c0-17.5 14.2-31.7 31.7-31.7l0 0c17.5 0 31.7 14.2 31.7 31.7L342.1 734.3z"></path>
|
|
52
|
+
<path d="M493.8 734.3c0 17.5-14.2 31.7-31.7 31.7l0 0c-17.5 0-31.7-14.2-31.7-31.7L430.4 387c0-17.5 14.2-31.7 31.7-31.7l0 0c17.5 0 31.7 14.2 31.7 31.7L493.8 734.3z"></path>
|
|
53
|
+
<path d="M797.3 734.3c0 17.5-14.2 31.7-31.7 31.7l0 0c-17.5 0-31.7-14.2-31.7-31.7L733.9 234.5c0-17.5 14.2-31.7 31.7-31.7l0 0c17.5 0 31.7 14.2 31.7 31.7L797.3 734.3z"></path>
|
|
54
|
+
<path d="M645.5 734.3c0 17.5-14.2 31.7-31.7 31.7l0 0c-17.5 0-31.7-14.2-31.7-31.7l0-97.2c0-17.5 14.2-31.7 31.7-31.7l0 0c17.5 0 31.7 14.2 31.7 31.7L645.5 734.3z"></path>
|
|
55
|
+
</svg>
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const BarChart = () => (
|
|
59
|
+
<svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" viewBox="0 0 1024 1024">
|
|
60
|
+
<path d="M131.072 156.16c0-17.92 14.336-31.744 31.744-31.744 17.92 0 31.744 14.336 31.744 31.744v712.192c0 17.92-14.336 31.744-31.744 31.744-17.92 0-31.744-14.336-31.744-31.744V156.16zM292.864 338.944c-17.408 0-31.744-14.336-31.744-31.744 0-17.408 14.336-31.744 31.744-31.744h245.248c17.408 0 31.744 14.336 31.744 31.744 0 17.408-14.336 31.744-31.744 31.744h-245.248zM292.864 490.496c-17.408 0-31.744-14.336-31.744-31.744 0-17.408 14.336-31.744 31.744-31.744H640c17.408 0 31.744 14.336 31.744 31.744 0 17.408-14.336 31.744-31.744 31.744h-347.136zM292.864 794.112c-17.408 0-31.744-14.336-31.744-31.744 0-17.408 14.336-31.744 31.744-31.744h499.712c17.408 0 31.744 14.336 31.744 31.744 0 17.408-14.336 31.744-31.744 31.744h-499.712zM292.864 642.56c-17.408 0-31.744-14.336-31.744-31.744 0-17.408 14.336-31.744 31.744-31.744h97.28c17.408 0 31.744 14.336 31.744 31.744 0 17.408-14.336 31.744-31.744 31.744h-97.28z"></path>
|
|
61
|
+
</svg>
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const LineChart = () => (
|
|
65
|
+
<svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" viewBox="0 0 1024 1024">
|
|
66
|
+
<path d="M191 864c0 17.7-14.3 32-32 32l0 0c-17.7 0-32-14.3-32-32L127 160c0-17.7 14.3-32 32-32l0 0c17.7 0 32 14.3 32 32L191 864z"></path>
|
|
67
|
+
<path d="M159 896c-17.7 0-32-14.3-32-32l0 0c0-17.7 14.3-32 32-32l712 0c17.7 0 32 14.3 32 32l0 0c0 17.7-14.3 32-32 32L159 896z"></path>
|
|
68
|
+
<path d="M307.1 686.3c-12.4 12.4-32.4 12.4-44.8 0l0 0c-12.4-12.4-12.4-32.4 0-44.8l173.4-173.4c12.4-12.4 32.4-12.4 44.8 0l0 0c12.4 12.4 12.4 32.4 0 44.8L307.1 686.3z"></path>
|
|
69
|
+
<path d="M608.8 640c-12.4 12.4-32.4 12.4-44.8 0l0 0c-12.4-12.4-12.4-32.4 0-44.8l212.7-212.7c12.4-12.4 32.4-12.4 44.8 0l0 0c12.4 12.4 12.4 32.4 0 44.8L608.8 640z"></path>
|
|
70
|
+
<path d="M608 595.3c12.4 12.4 12.4 32.4 0 44.8l0 0c-12.4 12.4-32.4 12.4-44.8 0L436 512.8c-12.4-12.4-12.4-32.4 0-44.8l0 0c12.4-12.4 32.4-12.4 44.8 0L608 595.3z"></path>
|
|
71
|
+
</svg>
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const PieChart = () => (
|
|
75
|
+
<svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" viewBox="0 0 1024 1024">
|
|
76
|
+
<path d="M489.7 511 489 511 489 126.9c-201 12.3-360.1 179.2-360.1 383.3 0 212.1 171.9 384 384 384 106.5 0 202.9-43.4 272.5-113.4L489.7 511z"></path>
|
|
77
|
+
<path d="M773.1 237.2l6-6c-62.7-59.6-143.5-95.8-228.2-104l0 304.7L773.1 237.2z"></path>
|
|
78
|
+
<path d="M819.5 281.6 564.1 505.1 822 739c3-4 5.9-8.1 8.7-12.3 41.4-61.3 65.6-135.2 65.6-214.7C896.3 425.6 867.7 345.8 819.5 281.6z"></path>
|
|
79
|
+
</svg>
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
const AreaChart = () => (
|
|
83
|
+
<svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" viewBox="0 0 1024 1024">
|
|
84
|
+
<path d="M191 864c0 17.7-14.3 32-32 32l0 0c-17.7 0-32-14.3-32-32L127 160c0-17.7 14.3-32 32-32l0 0c17.7 0 32 14.3 32 32L191 864z"></path>
|
|
85
|
+
<path d="M159 896c-17.7 0-32-14.3-32-32l0 0c0-17.7 14.3-32 32-32l712 0c17.7 0 32 14.3 32 32l0 0c0 17.7-14.3 32-32 32L159 896z"></path>
|
|
86
|
+
<path d="M830.6 338.2 830.6 338.2c0.9-9.2-2.1-18.6-9.1-25.7-12.4-12.4-32.4-12.4-44.8 0L586 503.3 480.8 398.1c-6.2-6.2-14.4-9.3-22.5-9.3-8.1 0-16.3 3.1-22.5 9.3L262.4 571.5c-6 6-9.1 13.8-9.3 21.6 0 0.1 0 0.1 0 0.2l0 111.8c0 35.3 28.7 64 64 64l449.7 0c33.8 0 61.4-26.1 63.8-59.3l0 0 0-0.2c0.1-1.5 0.2-3 0.2-4.5L830.8 593.3c0-0.3-0.1-0.7-0.2-1L830.6 338.2z"></path>
|
|
87
|
+
</svg>
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
Icon.register({
|
|
91
|
+
'icon-area': (props) => <Icon component={AreaChart} {...props} />,
|
|
92
|
+
'icon-pie': (props) => <Icon component={PieChart} {...props} />,
|
|
93
|
+
'icon-radar': (props) => <Icon component={RadarChart} {...props} />,
|
|
94
|
+
'icon-funnel': (props) => <Icon component={FunnelChart} {...props} />,
|
|
95
|
+
'icon-line': (props) => <Icon component={LineChart} {...props} />,
|
|
96
|
+
'icon-bar': (props) => <Icon component={BarChart} {...props} />,
|
|
97
|
+
'icon-column': (props) => <Icon component={ColumnChart} {...props} />,
|
|
98
|
+
'icon-scatter': (props) => <Icon component={ScatterChart} {...props} />,
|
|
99
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { G2Plot } from '@nocobase/client';
|
|
2
|
+
import DataSetPreviewTable from '../DataSetPreviewTable';
|
|
3
|
+
|
|
4
|
+
const chartRenderComponentsMap = new Map();
|
|
5
|
+
chartRenderComponentsMap.set('G2Plot', G2Plot);
|
|
6
|
+
chartRenderComponentsMap.set('DataSetPreviewTable', DataSetPreviewTable);
|
|
7
|
+
export default chartRenderComponentsMap;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useChartQueryMetadataContext } from '../ChartQueryMetadataProvider';
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
|
|
4
|
+
const useFieldsById = (queryId: number) => {
|
|
5
|
+
const [fields, setFields] = useState([]);
|
|
6
|
+
const ctx = useChartQueryMetadataContext();
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
const chartQueryList = ctx?.data;
|
|
9
|
+
if (chartQueryList && Array.isArray(chartQueryList)) {
|
|
10
|
+
const currentQuery = chartQueryList.find((chartQuery) => chartQuery.id === queryId);
|
|
11
|
+
setFields(currentQuery?.fields);
|
|
12
|
+
}
|
|
13
|
+
}, [queryId]);
|
|
14
|
+
return {
|
|
15
|
+
fields,
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export { useFieldsById };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { registerValidateRules } from '@formily/core';
|
|
2
|
+
import {
|
|
3
|
+
SchemaComponentOptions,
|
|
4
|
+
SchemaInitializerContext,
|
|
5
|
+
SettingsCenterProvider,
|
|
6
|
+
useAPIClient,
|
|
7
|
+
} from '@nocobase/client';
|
|
8
|
+
import JSON5 from 'json5';
|
|
9
|
+
import React, { useContext } from 'react';
|
|
10
|
+
import { ChartBlockEngine } from './ChartBlockEngine';
|
|
11
|
+
import { ChartBlockInitializer } from './ChartBlockInitializer';
|
|
12
|
+
import { ChartQueryMetadataProvider } from './ChartQueryMetadataProvider';
|
|
13
|
+
import './Icons';
|
|
14
|
+
import { lang } from './locale';
|
|
15
|
+
import { CustomSelect } from './select';
|
|
16
|
+
import { QueriesTable } from './settings/QueriesTable';
|
|
17
|
+
|
|
18
|
+
registerValidateRules({
|
|
19
|
+
json5: (value, rule) => {
|
|
20
|
+
if (!value) {
|
|
21
|
+
return '';
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const val = JSON5.parse(value);
|
|
25
|
+
if (!isNaN(val)) {
|
|
26
|
+
return {
|
|
27
|
+
type: 'error',
|
|
28
|
+
message: lang('Invalid JSON format'),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
return '';
|
|
32
|
+
} catch (error) {
|
|
33
|
+
console.error(error);
|
|
34
|
+
return {
|
|
35
|
+
type: 'error',
|
|
36
|
+
message: lang('Invalid JSON format'),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
export default React.memo((props) => {
|
|
43
|
+
const api = useAPIClient();
|
|
44
|
+
const items = useContext(SchemaInitializerContext);
|
|
45
|
+
const children = items.BlockInitializers.items[0].children;
|
|
46
|
+
if (children) {
|
|
47
|
+
const hasChartItem = children.some((child) => child?.component === 'ChartBlockInitializer');
|
|
48
|
+
if (!hasChartItem) {
|
|
49
|
+
children.push({
|
|
50
|
+
key: 'chart',
|
|
51
|
+
type: 'item',
|
|
52
|
+
icon: 'PieChartOutlined',
|
|
53
|
+
title: '{{t("Chart",{ns:"charts"})}}',
|
|
54
|
+
component: 'ChartBlockInitializer',
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const validateSQL = (sql) => {
|
|
59
|
+
return new Promise((resolve) => {
|
|
60
|
+
api
|
|
61
|
+
.request({
|
|
62
|
+
url: 'chartsQueries:validate',
|
|
63
|
+
method: 'post',
|
|
64
|
+
data: {
|
|
65
|
+
sql,
|
|
66
|
+
},
|
|
67
|
+
})
|
|
68
|
+
.then(({ data }) => {
|
|
69
|
+
resolve(data?.data?.errorMessage);
|
|
70
|
+
})
|
|
71
|
+
.catch(() => {
|
|
72
|
+
resolve('Invalid SQL');
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
return (
|
|
77
|
+
<ChartQueryMetadataProvider>
|
|
78
|
+
<SettingsCenterProvider
|
|
79
|
+
settings={{
|
|
80
|
+
charts: {
|
|
81
|
+
title: '{{t("Charts", {ns:"charts"})}}',
|
|
82
|
+
icon: 'PieChartOutlined',
|
|
83
|
+
tabs: {
|
|
84
|
+
queries: {
|
|
85
|
+
title: '{{t("Queries", {ns:"charts"})}}',
|
|
86
|
+
component: QueriesTable,
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
}}
|
|
91
|
+
>
|
|
92
|
+
<SchemaComponentOptions
|
|
93
|
+
scope={{ validateSQL }}
|
|
94
|
+
components={{ CustomSelect, ChartBlockInitializer, ChartBlockEngine }}
|
|
95
|
+
>
|
|
96
|
+
<SchemaInitializerContext.Provider value={items}>{props.children}</SchemaInitializerContext.Provider>
|
|
97
|
+
</SchemaComponentOptions>
|
|
98
|
+
</SettingsCenterProvider>
|
|
99
|
+
</ChartQueryMetadataProvider>
|
|
100
|
+
);
|
|
101
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
Edit: 'Edit',
|
|
3
|
+
Delete: 'Delete',
|
|
4
|
+
Cancel: 'Cancel',
|
|
5
|
+
Submit: 'Submit',
|
|
6
|
+
Actions: 'Actions',
|
|
7
|
+
Title: 'Title',
|
|
8
|
+
Enable: 'Enable',
|
|
9
|
+
'SAML manager': 'SAML manager',
|
|
10
|
+
'SAML Providers': 'SAML Providers',
|
|
11
|
+
'Redirect url': 'Redirect url',
|
|
12
|
+
'SP entity id': 'SP entity id',
|
|
13
|
+
'Add provider': 'Add',
|
|
14
|
+
'Edit provider': 'Edit',
|
|
15
|
+
'Client id': 'Client id',
|
|
16
|
+
'Entity id or issuer': 'Entity id or issuer',
|
|
17
|
+
'Login Url': 'Login Url',
|
|
18
|
+
'Public cert': 'Public cert',
|
|
19
|
+
'Delete provider': 'Delete',
|
|
20
|
+
'Are you sure you want to delete it?': 'Are you sure you want to delete it?',
|
|
21
|
+
'Sign in button name, which will be displayed on the sign in page':
|
|
22
|
+
'Sign in button name, which will be displayed on the sign in page',
|
|
23
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { i18n } from '@nocobase/client';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
|
|
4
|
+
export const NAMESPACE = 'charts';
|
|
5
|
+
|
|
6
|
+
// i18n.addResources('zh-CN', NAMESPACE, zhCN);
|
|
7
|
+
// i18n.addResources('en-US', NAMESPACE, enUS);
|
|
8
|
+
// i18n.addResources('ja-JP', NAMESPACE, jaJP);
|
|
9
|
+
// i18n.addResources('ru-RU', NAMESPACE, ruRU);
|
|
10
|
+
// i18n.addResources('tr-TR', NAMESPACE, trTR);
|
|
11
|
+
|
|
12
|
+
export function lang(key: string) {
|
|
13
|
+
return i18n.t(key, { ns: NAMESPACE });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function useChartsTranslation() {
|
|
17
|
+
return useTranslation(NAMESPACE);
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
Edit: '编辑',
|
|
3
|
+
Delete: '删除',
|
|
4
|
+
Cancel: '取消',
|
|
5
|
+
Submit: '提交',
|
|
6
|
+
Actions: '操作',
|
|
7
|
+
Title: '名称',
|
|
8
|
+
Enable: '启用',
|
|
9
|
+
Chart: '图表',
|
|
10
|
+
Charts: '图表',
|
|
11
|
+
Queries: '查询列表',
|
|
12
|
+
'Select chart query': '选择图表数据',
|
|
13
|
+
'Select query data': '选择查询数据',
|
|
14
|
+
Type: '类型',
|
|
15
|
+
'Chart type': '图表类型',
|
|
16
|
+
'Chart title': '图表标题',
|
|
17
|
+
'Basic charts': '基础图表',
|
|
18
|
+
'More charts': '更多图表',
|
|
19
|
+
'Chart config': '图表配置',
|
|
20
|
+
'Add query': '添加查询',
|
|
21
|
+
'Edit query': '编辑查询',
|
|
22
|
+
'Invalid JSON format,must be an object array.': '无效的JSON格式,必须是对象数组。',
|
|
23
|
+
Area: '面积图',
|
|
24
|
+
Bar: '条形图',
|
|
25
|
+
Column: '柱状图',
|
|
26
|
+
Funnel: '漏斗图',
|
|
27
|
+
Line: '折线图',
|
|
28
|
+
Pie: '饼图',
|
|
29
|
+
Radar: '雷达图',
|
|
30
|
+
Scatter: '散点图',
|
|
31
|
+
'Edit chart block': '编辑图表区块',
|
|
32
|
+
'Chart preview': '图表预览',
|
|
33
|
+
'Delete queries': '删除查询列表',
|
|
34
|
+
'Delete query': '删除查询',
|
|
35
|
+
'Add chart query': '添加图表查询',
|
|
36
|
+
'Add SQL query': '添加SQL查询',
|
|
37
|
+
'Add JSON query': '添加JSON查询',
|
|
38
|
+
'Data preview': '数据预览',
|
|
39
|
+
'Category axis / Dimension': '类别轴 / 维度',
|
|
40
|
+
'Value axis / Metrics': '值轴 / 度量',
|
|
41
|
+
'JSON config': 'JSON 配置',
|
|
42
|
+
'Json config references': 'JSON配置参考',
|
|
43
|
+
'Create chart block': '创建图表区块',
|
|
44
|
+
'Invalid JSON format': '无效的JSON格式',
|
|
45
|
+
'Json config references: ': 'JSON配置参考: ',
|
|
46
|
+
'Sector Angle / Metric': '扇形角 / 度量',
|
|
47
|
+
'Sector label / Dimensional': '扇形标签 / 维度',
|
|
48
|
+
'Color legend / Dimensional': '颜色系列 / 维度',
|
|
49
|
+
'Funnel Layer Width/Metrics': '漏斗层宽度 / 度量',
|
|
50
|
+
'Branch Tags/Dimensions': '分支标签 / 维度',
|
|
51
|
+
'Branch Length/Metrics': '分支长度 / 度量',
|
|
52
|
+
'Please check the chart config': '请检查图表配置',
|
|
53
|
+
'1 「time」or 「Ordered Noun」 field,1 「Numerical」 field,1 「Unordered Noun」 field (optional)':
|
|
54
|
+
'1 个「时间」或「有序名词」字段,1 个「数值」字段,1 个「无序名词」字段(可选)',
|
|
55
|
+
'1 「time」 or 「ordered noun」 field, 1 「value」 field, 0~ 1 「unordered noun」':
|
|
56
|
+
'1 个「时间」或「有序名词」字段,1 个「数值」字段,0 ~ 1 个「无序名词」',
|
|
57
|
+
'1 「time」 or 「ordered noun」 field, 1 「value」 field, 0 to 1 「unordered noun」':
|
|
58
|
+
'1 个「时间」或「有序名词」字段,1 个「数值」字段,0 ~ 1 个「无序名词」',
|
|
59
|
+
'1 「Unordered Noun」 field, 1 「Numeric」 field': '1 个「无序名词」字段,1 个「数值」字段',
|
|
60
|
+
'1 「Time」 or 「Order Noun」 field, 1 「Value」 field': '1 个「时间」或「有序名词」字段,1 个「数值」字段',
|
|
61
|
+
'1~ 2 「Unordered Noun」 fields, 1 「Numeric」 field': '1 ~ 2 个「无序名词」字段,1 个「数值」字段',
|
|
62
|
+
'1 「Numeric」 field, 0~ 1 「Unordered Noun」 field': '1 个「数值」字段,0 ~ 1 个「无序名词」字段',
|
|
63
|
+
};
|