@nocobase/plugin-map 0.8.1-alpha.3

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.
Files changed (104) hide show
  1. package/LICENSE +201 -0
  2. package/client.d.ts +4 -0
  3. package/client.js +30 -0
  4. package/lib/client/components/AMap.d.ts +13 -0
  5. package/lib/client/components/AMap.js +502 -0
  6. package/lib/client/components/Configuration.d.ts +2 -0
  7. package/lib/client/components/Configuration.js +167 -0
  8. package/lib/client/components/Designer.d.ts +2 -0
  9. package/lib/client/components/Designer.js +308 -0
  10. package/lib/client/components/Map.d.ts +6 -0
  11. package/lib/client/components/Map.js +65 -0
  12. package/lib/client/components/ReadPretty.d.ts +2 -0
  13. package/lib/client/components/ReadPretty.js +81 -0
  14. package/lib/client/components/Search.d.ts +6 -0
  15. package/lib/client/components/Search.js +155 -0
  16. package/lib/client/constants.d.ts +4 -0
  17. package/lib/client/constants.js +17 -0
  18. package/lib/client/fields/circle.d.ts +2 -0
  19. package/lib/client/fields/circle.js +37 -0
  20. package/lib/client/fields/index.d.ts +2 -0
  21. package/lib/client/fields/index.js +22 -0
  22. package/lib/client/fields/lineString.d.ts +2 -0
  23. package/lib/client/fields/lineString.js +37 -0
  24. package/lib/client/fields/point.d.ts +2 -0
  25. package/lib/client/fields/point.js +37 -0
  26. package/lib/client/fields/polygon.d.ts +2 -0
  27. package/lib/client/fields/polygon.js +37 -0
  28. package/lib/client/fields/schema.d.ts +99 -0
  29. package/lib/client/fields/schema.js +79 -0
  30. package/lib/client/hooks/index.d.ts +1 -0
  31. package/lib/client/hooks/index.js +18 -0
  32. package/lib/client/hooks/useMapConfiguration.d.ts +2 -0
  33. package/lib/client/hooks/useMapConfiguration.js +33 -0
  34. package/lib/client/index.d.ts +3 -0
  35. package/lib/client/index.js +80 -0
  36. package/lib/client/initialize.d.ts +4 -0
  37. package/lib/client/initialize.js +67 -0
  38. package/lib/client/locales/en-US.d.ts +2 -0
  39. package/lib/client/locales/en-US.js +9 -0
  40. package/lib/client/locales/index.d.ts +4 -0
  41. package/lib/client/locales/index.js +56 -0
  42. package/lib/client/locales/zh-CN.d.ts +43 -0
  43. package/lib/client/locales/zh-CN.js +51 -0
  44. package/lib/index.d.ts +1 -0
  45. package/lib/index.js +15 -0
  46. package/lib/server/actions/index.d.ts +3 -0
  47. package/lib/server/actions/index.js +66 -0
  48. package/lib/server/collections/mapConfiguration.d.ts +3 -0
  49. package/lib/server/collections/mapConfiguration.js +30 -0
  50. package/lib/server/constants.d.ts +1 -0
  51. package/lib/server/constants.js +8 -0
  52. package/lib/server/fields/circle.d.ts +13 -0
  53. package/lib/server/fields/circle.js +84 -0
  54. package/lib/server/fields/index.d.ts +4 -0
  55. package/lib/server/fields/index.js +57 -0
  56. package/lib/server/fields/lineString.d.ts +13 -0
  57. package/lib/server/fields/lineString.js +91 -0
  58. package/lib/server/fields/point.d.ts +13 -0
  59. package/lib/server/fields/point.js +95 -0
  60. package/lib/server/fields/polygon.d.ts +13 -0
  61. package/lib/server/fields/polygon.js +89 -0
  62. package/lib/server/helpers/index.d.ts +6 -0
  63. package/lib/server/helpers/index.js +44 -0
  64. package/lib/server/index.d.ts +1 -0
  65. package/lib/server/index.js +15 -0
  66. package/lib/server/plugin.d.ts +11 -0
  67. package/lib/server/plugin.js +88 -0
  68. package/package.json +19 -0
  69. package/server.d.ts +4 -0
  70. package/server.js +30 -0
  71. package/src/client/components/AMap.tsx +369 -0
  72. package/src/client/components/Configuration.tsx +91 -0
  73. package/src/client/components/Designer.tsx +260 -0
  74. package/src/client/components/Map.tsx +29 -0
  75. package/src/client/components/ReadPretty.tsx +34 -0
  76. package/src/client/components/Search.tsx +93 -0
  77. package/src/client/constants.ts +6 -0
  78. package/src/client/fields/circle.ts +23 -0
  79. package/src/client/fields/index.ts +16 -0
  80. package/src/client/fields/lineString.ts +23 -0
  81. package/src/client/fields/point.ts +24 -0
  82. package/src/client/fields/polygon.ts +23 -0
  83. package/src/client/fields/schema.ts +57 -0
  84. package/src/client/hooks/index.ts +1 -0
  85. package/src/client/hooks/useMapConfiguration.ts +15 -0
  86. package/src/client/index.tsx +43 -0
  87. package/src/client/initialize.tsx +33 -0
  88. package/src/client/locales/en-US.ts +5 -0
  89. package/src/client/locales/index.ts +22 -0
  90. package/src/client/locales/zh-CN.ts +45 -0
  91. package/src/index.ts +1 -0
  92. package/src/server/__tests__/fields.test.ts +168 -0
  93. package/src/server/actions/index.ts +46 -0
  94. package/src/server/collections/mapConfiguration.ts +27 -0
  95. package/src/server/constants.ts +1 -0
  96. package/src/server/fields/.gitkeep +0 -0
  97. package/src/server/fields/circle.ts +50 -0
  98. package/src/server/fields/index.ts +4 -0
  99. package/src/server/fields/lineString.ts +56 -0
  100. package/src/server/fields/point.ts +59 -0
  101. package/src/server/fields/polygon.ts +56 -0
  102. package/src/server/helpers/index.ts +25 -0
  103. package/src/server/index.ts +1 -0
  104. package/src/server/plugin.ts +46 -0
@@ -0,0 +1,15 @@
1
+ import { useRequest } from "@nocobase/client";
2
+
3
+ export const MapConfigurationResourceKey = 'map-configuration';
4
+
5
+ export const useMapConfiguration = (type: string) => {
6
+ return useRequest({
7
+ resource: MapConfigurationResourceKey,
8
+ action: 'get',
9
+ params: {
10
+ type,
11
+ },
12
+ }).data?.data;
13
+ }
14
+
15
+
@@ -0,0 +1,43 @@
1
+ import {
2
+ CollectionManagerContext,
3
+ CurrentAppInfoProvider,
4
+ SchemaComponentOptions,
5
+ SettingsCenterProvider,
6
+ } from '@nocobase/client';
7
+ import React, { useContext } from 'react';
8
+ import Configuration from './components/Configuration';
9
+ import Map from './components/Map';
10
+ import { interfaces } from './fields';
11
+ import { Initialize } from './initialize';
12
+ import { useMapTranslation } from './locales';
13
+
14
+ export default React.memo((props) => {
15
+ const ctx = useContext(CollectionManagerContext);
16
+ const { t } = useMapTranslation();
17
+ return (
18
+ <CurrentAppInfoProvider>
19
+ <Initialize>
20
+ <SettingsCenterProvider
21
+ settings={{
22
+ 'map-configuration': {
23
+ title: t('Map Manager'),
24
+ icon: 'EnvironmentOutlined',
25
+ tabs: {
26
+ configuration: {
27
+ title: t('Configuration'),
28
+ component: Configuration,
29
+ },
30
+ },
31
+ },
32
+ }}
33
+ >
34
+ <SchemaComponentOptions components={{ Map }}>
35
+ <CollectionManagerContext.Provider value={{ ...ctx, interfaces: { ...ctx.interfaces, ...interfaces } }}>
36
+ {props.children}
37
+ </CollectionManagerContext.Provider>
38
+ </SchemaComponentOptions>
39
+ </SettingsCenterProvider>
40
+ </Initialize>
41
+ </CurrentAppInfoProvider>
42
+ );
43
+ });
@@ -0,0 +1,33 @@
1
+ import React from 'react';
2
+ import { registerField, registerGroup, useCurrentAppInfo } from '@nocobase/client';
3
+ import { generateNTemplate } from './locales';
4
+ import './locales';
5
+ import { fields } from './fields';
6
+ import { useEffect } from 'react';
7
+
8
+ export const useRegisterInterface = () => {
9
+ const { data } = useCurrentAppInfo() || {};
10
+ useEffect(() => {
11
+ const dialect = data?.database.dialect;
12
+ if (!dialect) return;
13
+
14
+ registerGroup(fields[0].group, {
15
+ label: generateNTemplate('Map-based geometry'),
16
+ order: 51,
17
+ });
18
+
19
+ fields.forEach((field) => {
20
+ if (Array.isArray(field.dialects)) {
21
+ if (!field.dialects.includes(dialect)) {
22
+ return;
23
+ }
24
+ }
25
+ registerField(field.group, field.title, field);
26
+ });
27
+ }, [data]);
28
+ };
29
+
30
+ export const Initialize: React.FC = (props) => {
31
+ useRegisterInterface();
32
+ return <React.Fragment>{props.children}</React.Fragment>;
33
+ };
@@ -0,0 +1,5 @@
1
+ const locale = {
2
+
3
+ }
4
+
5
+ export default locale;
@@ -0,0 +1,22 @@
1
+ import { i18n } from '@nocobase/client';
2
+ import { useTranslation } from 'react-i18next';
3
+
4
+ import enUS from './en-US';
5
+ import zhCN from './zh-CN';
6
+
7
+ export const NAMESPACE = 'map';
8
+
9
+ i18n.addResources('zh-CN', NAMESPACE, zhCN);
10
+ i18n.addResources('en-US', NAMESPACE, enUS);
11
+
12
+ export function lang(key: string) {
13
+ return i18n.t(key, { ns: NAMESPACE });
14
+ }
15
+
16
+ export function generateNTemplate(key: string) {
17
+ return `{{t('${key}', { ns: '${NAMESPACE}' })}}`;
18
+ }
19
+
20
+ export function useMapTranslation() {
21
+ return useTranslation(NAMESPACE);
22
+ }
@@ -0,0 +1,45 @@
1
+ const locale = {
2
+ 'Map-based geometry': '基于地图的几何图形',
3
+ 'Map type': '地图类型',
4
+ 'Point': '点',
5
+ 'Line': '线',
6
+ 'Circle': '圆',
7
+ 'Polygon': '多边形',
8
+ 'Access key': '访问密钥',
9
+ 'securityJsCode or serviceHost': 'securityJsCode 或 serviceHost',
10
+ 'AMap': '高德地图',
11
+ 'Google Maps': '谷歌地图',
12
+ 'Clear': '清空',
13
+ 'Click to select the starting point and double-click to end the drawing': '点击选择起点,双击结束绘制',
14
+ 'Clear the canvas': '清空画布',
15
+ 'Are you sure to clear the canvas?': '您确定要清空画布吗?',
16
+ 'Confirm': '确定',
17
+ 'Cancel': '取消',
18
+ 'Enter keywords to search': '输入地方名关键字搜索(必须包含省/市)',
19
+ 'The AccessKey is incorrect, please check it': '访问密钥不正确,请检查',
20
+ 'Please configure the AMap securityCode or serviceHost correctly': '请正确配置高德地图 securityCode 或 serviceHost',
21
+ 'Map Manager': '地图管理',
22
+ 'Configuration': '配置',
23
+ 'Saved successfully': '保存成功',
24
+ 'Saved failed': '保存失败',
25
+ 'Edit': '编辑',
26
+ 'Save': '保存',
27
+ 'Please configure the AccessKey and SecurityJsCode first': '请先配置 AccessKey 和 SecurityJsCode',
28
+ 'Go to the configuration page': '前往配置页面',
29
+ 'Zoom': '缩放',
30
+ 'Set default zoom level': '设置默认缩放级别',
31
+ 'The default zoom level of the map': '地图默认缩放级别',
32
+ // Designer
33
+ 'Edit field title': '编辑字段标题',
34
+ 'Field title': '字段标题',
35
+ 'Edit tooltip': '编辑提示信息',
36
+ 'Delete field': '删除字段',
37
+ "Required": "必填",
38
+ 'Pattern': '模式',
39
+ "Editable": "可编辑",
40
+ "Readonly": "只读(禁止编辑)",
41
+ "Easy-reading": "只读(阅读模式)",
42
+ "Edit description": "编辑描述",
43
+ }
44
+
45
+ export default locale;
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export { default } from './server';
@@ -0,0 +1,168 @@
1
+ import Database from '@nocobase/database';
2
+ import { mockDatabase } from '@nocobase/test';
3
+ import { PointField, CircleField, PolygonField, LineStringField } from '../fields';
4
+
5
+ const data = {
6
+ polygon: [
7
+ [114.081074, 22.563646],
8
+ [114.147335, 22.559207],
9
+ [114.134975, 22.531621],
10
+ [114.09103, 22.520045],
11
+ [114.033695, 22.575376],
12
+ [114.025284, 22.55461],
13
+ [114.033523, 22.533048],
14
+ ],
15
+ point: [114.048868, 22.554927],
16
+ circle: [114.058996, 22.549695, 4171],
17
+ lineString: [
18
+ [114.047323, 22.534158],
19
+ [114.120966, 22.544146],
20
+ ],
21
+ };
22
+ describe('fields', () => {
23
+ let db: Database;
24
+
25
+ beforeEach(async () => {
26
+ db = mockDatabase();
27
+ db.registerFieldTypes({
28
+ point: PointField,
29
+ circle: CircleField,
30
+ polygon: PolygonField,
31
+ lineString: LineStringField,
32
+ });
33
+ });
34
+
35
+ afterEach(async () => {
36
+ await db.close();
37
+ });
38
+
39
+ const createCollection = async () => {
40
+ const fields = [
41
+ {
42
+ type: 'point',
43
+ name: 'point',
44
+ },
45
+ {
46
+ type: 'polygon',
47
+ name: 'polygon',
48
+ },
49
+ {
50
+ type: 'circle',
51
+ name: 'circle',
52
+ },
53
+ {
54
+ type: 'lineString',
55
+ name: 'lineString',
56
+ },
57
+ ];
58
+ const Test = db.collection({
59
+ name: 'tests',
60
+ fields,
61
+ });
62
+
63
+ await db.sync();
64
+
65
+ return Test;
66
+ };
67
+ it('define', async () => {
68
+ const Test = await createCollection();
69
+ await Test.model.create();
70
+ });
71
+
72
+ it('create', async () => {
73
+ const Test = await createCollection();
74
+ const model = await Test.model.create(data);
75
+ expect(model.get()).toMatchObject(data);
76
+ });
77
+
78
+ it('find', async () => {
79
+ const Test = await createCollection();
80
+ await Test.model.create(data);
81
+ expect(await Test.model.findOne()).toMatchObject(data);
82
+ });
83
+
84
+ it('set and get', async () => {
85
+ const Test = await createCollection();
86
+ const model = await Test.model.create();
87
+ model.set('point', [1, 2]);
88
+ expect(model.get('point')).toMatchObject([1, 2]);
89
+ model.set('polygon', [
90
+ [3, 4],
91
+ [5, 6],
92
+ ]);
93
+ expect(model.get('polygon')).toMatchObject([
94
+ [3, 4],
95
+ [5, 6],
96
+ ]);
97
+ model.set('lineString', [[5, 6], [7, 8]]);
98
+ expect(model.get('lineString')).toMatchObject([[5, 6], [7, 8]]);
99
+ model.set('circle', [1, 2, 0.5]);
100
+ expect(model.get('circle')).toMatchObject([1, 2, 0.5]);
101
+ });
102
+
103
+ it('create and update', async () => {
104
+ const Test = await createCollection();
105
+ const model = await Test.model.create(data);
106
+ await model.save();
107
+ const findOne = () =>
108
+ db.getRepository('tests').findOne({
109
+ except: ['createdAt', 'updatedAt', 'id'],
110
+ });
111
+ expect(await findOne()).toMatchObject(data);
112
+
113
+ await model.update({
114
+ point: [1, 2],
115
+ polygon: null,
116
+ });
117
+
118
+ expect(await findOne()).toMatchInlineSnapshot(`
119
+ Object {
120
+ "circle": Array [
121
+ 114.058996,
122
+ 22.549695,
123
+ 4171,
124
+ ],
125
+ "lineString": Array [
126
+ Array [
127
+ 114.047323,
128
+ 22.534158,
129
+ ],
130
+ Array [
131
+ 114.120966,
132
+ 22.544146,
133
+ ],
134
+ ],
135
+ "point": Array [
136
+ 1,
137
+ 2,
138
+ ],
139
+ "polygon": null,
140
+ }
141
+ `);
142
+ });
143
+
144
+ it('empty', async () => {
145
+ const Test = await createCollection();
146
+ const model = await Test.model.create({
147
+ circle: null,
148
+ lineString: null,
149
+ point: null,
150
+ polygon: null,
151
+ });
152
+ await model.save();
153
+
154
+ const findOne = () =>
155
+ db.getRepository('tests').findOne({
156
+ except: ['createdAt', 'updatedAt', 'id'],
157
+ });
158
+
159
+ expect(await findOne()).toMatchInlineSnapshot(`
160
+ Object {
161
+ "circle": null,
162
+ "lineString": null,
163
+ "point": null,
164
+ "polygon": null,
165
+ }
166
+ `);
167
+ });
168
+ });
@@ -0,0 +1,46 @@
1
+ import { Context } from '@nocobase/actions';
2
+ import { MapConfigurationCollectionName } from '../constants';
3
+
4
+ export const getConfiguration = async (ctx: Context, next) => {
5
+ const {
6
+ params: { type },
7
+ } = ctx.action;
8
+
9
+ const repo = ctx.db.getRepository(MapConfigurationCollectionName);
10
+ const record = await repo.findOne({
11
+ filter: {
12
+ type,
13
+ },
14
+ });
15
+
16
+ ctx.body = record
17
+ return next();
18
+ };
19
+
20
+ export const setConfiguration = async (ctx: Context, next) => {
21
+ const {
22
+ params: values,
23
+ } = ctx.action;
24
+ const repo = ctx.db.getRepository(MapConfigurationCollectionName);
25
+ const record = await repo.findOne({
26
+ filter: {
27
+ type: values.type,
28
+ },
29
+ });
30
+
31
+ if (record) {
32
+ await repo.update({
33
+ values,
34
+ filter: {
35
+ type: values.type,
36
+ }
37
+ });
38
+ } else {
39
+ await repo.create({
40
+ values,
41
+ })
42
+ }
43
+
44
+ ctx.body = 'ok'
45
+ return next();
46
+ };
@@ -0,0 +1,27 @@
1
+ import { CollectionOptions } from "@nocobase/client";
2
+ import { MapConfigurationCollectionName } from "../constants";
3
+
4
+ export default {
5
+ name: MapConfigurationCollectionName,
6
+ title: '{{t("Map Manager")}}',
7
+ fields: [
8
+ {
9
+ title: 'Access key',
10
+ comment: '访问密钥',
11
+ name: 'accessKey',
12
+ type: 'string'
13
+ },
14
+ {
15
+ title: 'securityJsCode',
16
+ comment: 'securityJsCode or serviceHOST',
17
+ name: 'securityJsCode',
18
+ type: 'string'
19
+ },
20
+ {
21
+ title: 'Map type',
22
+ comment: '地图类型',
23
+ name: 'type',
24
+ type: 'string',
25
+ }
26
+ ]
27
+ } as CollectionOptions
@@ -0,0 +1 @@
1
+ export const MapConfigurationCollectionName = 'mapConfiguration';
File without changes
@@ -0,0 +1,50 @@
1
+ import { BaseColumnFieldOptions, Field, FieldContext } from '@nocobase/database';
2
+ import { DataTypes } from 'sequelize';
3
+ import { isPg, toValue } from '../helpers';
4
+
5
+ class Circle extends DataTypes.ABSTRACT {
6
+ key = 'Circle';
7
+ }
8
+
9
+
10
+ export class CircleField extends Field {
11
+ constructor(options?: any, context?: FieldContext) {
12
+ const { name } = options
13
+ super(
14
+ {
15
+ get() {
16
+ const value = this.getDataValue(name);
17
+ if (isPg(context)) {
18
+ if (typeof value === 'string') {
19
+ return toValue(`(${value})`)
20
+ }
21
+ return value ? [value.x, value.y, value.radius] : null
22
+ } else {
23
+ return value
24
+ }
25
+ },
26
+ set(value) {
27
+ if (!value?.length) value = null
28
+ else if (isPg(context)) {
29
+ value = value.join(',')
30
+ }
31
+ this.setDataValue(name, value)
32
+ },
33
+ ...options,
34
+ },
35
+ context,
36
+ );
37
+ }
38
+
39
+ get dataType() {
40
+ if (isPg(this.context)) {
41
+ return Circle;
42
+ } else {
43
+ return DataTypes.JSON
44
+ }
45
+ }
46
+ }
47
+
48
+ export interface CircleFieldOptions extends BaseColumnFieldOptions {
49
+ type: 'circle';
50
+ }
@@ -0,0 +1,4 @@
1
+ export * from './point'
2
+ export * from './lineString'
3
+ export * from './polygon'
4
+ export * from './circle'
@@ -0,0 +1,56 @@
1
+ import { BaseColumnFieldOptions, Field, FieldContext } from '@nocobase/database';
2
+ import { DataTypes } from 'sequelize';
3
+ import { isMysql, isPg, isSqlite, joinComma, toValue } from '../helpers';
4
+
5
+ class LineString extends DataTypes.ABSTRACT {
6
+ key = 'Path';
7
+ }
8
+
9
+ export class LineStringField extends Field {
10
+ constructor(options?: any, context?: FieldContext) {
11
+ const { name } = options
12
+ super(
13
+ {
14
+ get() {
15
+ const value = this.getDataValue(name);
16
+ if (isPg(context)) {
17
+ return toValue(value)
18
+ } else if (isMysql(context)) {
19
+ return value?.coordinates || null
20
+ } else {
21
+ return value
22
+ }
23
+ },
24
+ set(value) {
25
+ if (!value?.length) value = null
26
+ else if (isPg(context)) {
27
+ value = joinComma(value.map(joinComma))
28
+ } else if (isMysql(context)) {
29
+ value = {
30
+ type: 'LineString',
31
+ coordinates: value
32
+ }
33
+ }
34
+ this.setDataValue(name, value)
35
+ },
36
+ ...options,
37
+ },
38
+ context,
39
+ );
40
+ }
41
+
42
+ get dataType() {
43
+ if (isPg(this.context)) {
44
+ return LineString
45
+ } if (isMysql(this.context)) {
46
+ return DataTypes.GEOMETRY('LINESTRING');
47
+ } else {
48
+ return DataTypes.JSON;
49
+ }
50
+ }
51
+
52
+ }
53
+
54
+ export interface LineStringOptions extends BaseColumnFieldOptions {
55
+ type: 'lineString';
56
+ }
@@ -0,0 +1,59 @@
1
+ import { BaseColumnFieldOptions, Field, FieldContext } from '@nocobase/database';
2
+ import { DataTypes } from 'sequelize';
3
+ import { isMysql, isPg, joinComma, toValue } from '../helpers';
4
+
5
+ class Point extends DataTypes.ABSTRACT {
6
+ key = 'Point';
7
+ }
8
+
9
+ export class PointField extends Field {
10
+ constructor(options?: any, context?: FieldContext) {
11
+ const { name } = options
12
+ super(
13
+ {
14
+ get() {
15
+ const value = this.getDataValue(name);
16
+ if (isPg(context)) {
17
+ if (typeof value === 'string') {
18
+ return toValue(value)
19
+ }
20
+ return value ? [value.x, value.y] : null
21
+ } else if (isMysql(context)) {
22
+ return value?.coordinates || null
23
+ } else {
24
+ return value
25
+ }
26
+ },
27
+ set(value) {
28
+ if (!value?.length) value = null
29
+ else if (isPg(context)) {
30
+ value = joinComma(value)
31
+ } else if (isMysql(context)) {
32
+ value = {
33
+ type: 'Point',
34
+ coordinates: value
35
+ }
36
+ }
37
+ this.setDataValue(name, value)
38
+ },
39
+ ...options,
40
+ },
41
+ context,
42
+ );
43
+ }
44
+
45
+ get dataType() {
46
+ if (isPg(this.context)) {
47
+ return Point;
48
+ } if (isMysql(this.context)) {
49
+ return DataTypes.GEOMETRY('POINT');
50
+ } else {
51
+ return DataTypes.JSON;
52
+ }
53
+ }
54
+
55
+ }
56
+
57
+ export interface PointFieldOptions extends BaseColumnFieldOptions {
58
+ type: 'point';
59
+ }
@@ -0,0 +1,56 @@
1
+ import { BaseColumnFieldOptions, Field, FieldContext } from '@nocobase/database';
2
+ import { DataTypes } from 'sequelize';
3
+ import { isMysql, isPg, joinComma, toValue } from '../helpers';
4
+
5
+ class Polygon extends DataTypes.ABSTRACT {
6
+ key = 'Polygon'
7
+ }
8
+
9
+ export class PolygonField extends Field {
10
+ constructor(options?: any, context?: FieldContext) {
11
+ const { name } = options
12
+ super(
13
+ {
14
+ get() {
15
+ const value = this.getDataValue(name)
16
+ if (isPg(context)) {
17
+ return toValue(value)
18
+ } else if (isMysql(context)) {
19
+ return value?.coordinates[0].slice(0, -1) || null
20
+ } else {
21
+ return value
22
+ }
23
+ },
24
+ set(value) {
25
+ if (!value?.length) value = null
26
+ else if (isPg(context)) {
27
+ value = joinComma(value.map((item: any) => joinComma(item)))
28
+ } else if (isMysql(context)) {
29
+ value = {
30
+ type: 'Polygon',
31
+ coordinates: [value.concat([value[0]])]
32
+ }
33
+ }
34
+ this.setDataValue(name, value)
35
+ },
36
+ ...options,
37
+ },
38
+ context,
39
+ );
40
+ }
41
+
42
+ get dataType() {
43
+ if (isPg(this.context)) {
44
+ return Polygon;
45
+ } else if (isMysql(this.context)) {
46
+ return DataTypes.GEOMETRY('POLYGON');
47
+ } else {
48
+ return DataTypes.JSON;
49
+ }
50
+ }
51
+
52
+ }
53
+
54
+ export interface PolygonFieldOptions extends BaseColumnFieldOptions {
55
+ type: 'polygon';
56
+ }
@@ -0,0 +1,25 @@
1
+ export const joinComma = (value: any[]) => {
2
+ if (!value) return null
3
+ return `(${value.join(',')})`
4
+ }
5
+
6
+ export const toValue = (value?: string) => {
7
+ if (!value) return null
8
+ return JSON.parse(value.replace(/\(/g, '[').replace(/\)/g, ']'))
9
+ }
10
+
11
+ export const getDialect = (ctx) => {
12
+ return (ctx.db || ctx.database).sequelize.getDialect();
13
+ };
14
+
15
+ export const isPg = (ctx) => {
16
+ return getDialect(ctx) === 'postgres';
17
+ };
18
+
19
+ export const isSqlite = (ctx) => {
20
+ return getDialect(ctx) === 'sqlite';
21
+ };
22
+
23
+ export const isMysql = (ctx) => {
24
+ return getDialect(ctx) === 'mysql';
25
+ };
@@ -0,0 +1 @@
1
+ export { default } from './plugin';