bi-sdk-react 0.0.1

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 (146) hide show
  1. package/dist/es/css/bi-sdk.css +1 -0
  2. package/dist/es/js/bi-sdk.es.js +795 -0
  3. package/dist/es/js/bi-sdk.es.js.LICENSE.txt +9 -0
  4. package/dist/types/components/PageDesigner.d.ts +10 -0
  5. package/dist/types/components/context/DesignerContext.d.ts +15 -0
  6. package/dist/types/components/context/EnvContext.d.ts +15 -0
  7. package/dist/types/components/dnd/DropContainer.d.ts +21 -0
  8. package/dist/types/components/example.d.ts +225 -0
  9. package/dist/types/components/hooks/datasource.d.ts +1 -0
  10. package/dist/types/components/hooks/useDeepCompareEffect.d.ts +1 -0
  11. package/dist/types/components/icon/IconFont.d.ts +6 -0
  12. package/dist/types/components/index.d.ts +10 -0
  13. package/dist/types/components/layout/PageCanvas.d.ts +6 -0
  14. package/dist/types/components/layout/PageItem.d.ts +27 -0
  15. package/dist/types/components/panel/AiPanel.d.ts +8 -0
  16. package/dist/types/components/panel/CascadePanel.d.ts +2 -0
  17. package/dist/types/components/panel/ChatInput.d.ts +28 -0
  18. package/dist/types/components/panel/CodePanel.d.ts +2 -0
  19. package/dist/types/components/panel/ComponentPanel.d.ts +2 -0
  20. package/dist/types/components/panel/DatasourcePanel.d.ts +2 -0
  21. package/dist/types/components/panel/LayerPanel.d.ts +2 -0
  22. package/dist/types/components/panel/PaneHeader.d.ts +6 -0
  23. package/dist/types/components/panel/PropertiesPanel.d.ts +2 -0
  24. package/dist/types/components/panel/ScriptPanel.d.ts +2 -0
  25. package/dist/types/components/panel/VariablesPanel.d.ts +2 -0
  26. package/dist/types/components/panel/index.d.ts +9 -0
  27. package/dist/types/components/plugins/@antd/index.d.ts +22 -0
  28. package/dist/types/components/plugins/@antd/item-props/ButtonProps.d.ts +8 -0
  29. package/dist/types/components/plugins/@antd/item-props/CapsuleProps.d.ts +13 -0
  30. package/dist/types/components/plugins/@antd/item-props/CardProps.d.ts +8 -0
  31. package/dist/types/components/plugins/@antd/item-props/CheckboxProps.d.ts +13 -0
  32. package/dist/types/components/plugins/@antd/item-props/ColProps.d.ts +12 -0
  33. package/dist/types/components/plugins/@antd/item-props/DatePickerProps.d.ts +8 -0
  34. package/dist/types/components/plugins/@antd/item-props/EchartsProps.d.ts +6 -0
  35. package/dist/types/components/plugins/@antd/item-props/HtmlProps.d.ts +6 -0
  36. package/dist/types/components/plugins/@antd/item-props/ImageProps.d.ts +10 -0
  37. package/dist/types/components/plugins/@antd/item-props/InputNumberProps.d.ts +9 -0
  38. package/dist/types/components/plugins/@antd/item-props/InputProps.d.ts +10 -0
  39. package/dist/types/components/plugins/@antd/item-props/ListProps.d.ts +10 -0
  40. package/dist/types/components/plugins/@antd/item-props/PageHeaderProps.d.ts +7 -0
  41. package/dist/types/components/plugins/@antd/item-props/RowProps.d.ts +6 -0
  42. package/dist/types/components/plugins/@antd/item-props/SelectProps.d.ts +16 -0
  43. package/dist/types/components/plugins/@antd/item-props/SpaceProps.d.ts +7 -0
  44. package/dist/types/components/plugins/@antd/item-props/SwitchProps.d.ts +6 -0
  45. package/dist/types/components/plugins/@antd/item-props/TableProps.d.ts +15 -0
  46. package/dist/types/components/plugins/@antd/item-props/TextProps.d.ts +6 -0
  47. package/dist/types/components/plugins/@antd/item-props/index.d.ts +19 -0
  48. package/dist/types/components/plugins/@antd/item-props/types.d.ts +5 -0
  49. package/dist/types/components/plugins/@antd/items/ButtonRender.d.ts +14 -0
  50. package/dist/types/components/plugins/@antd/items/CapsuleRender.d.ts +14 -0
  51. package/dist/types/components/plugins/@antd/items/CardRender.d.ts +12 -0
  52. package/dist/types/components/plugins/@antd/items/CheckboxRender.d.ts +14 -0
  53. package/dist/types/components/plugins/@antd/items/ColRender.d.ts +13 -0
  54. package/dist/types/components/plugins/@antd/items/DatePickerRender.d.ts +14 -0
  55. package/dist/types/components/plugins/@antd/items/EchartsRender.d.ts +10 -0
  56. package/dist/types/components/plugins/@antd/items/HtmlRender.d.ts +20 -0
  57. package/dist/types/components/plugins/@antd/items/ImageRender.d.ts +10 -0
  58. package/dist/types/components/plugins/@antd/items/InputNumberRender.d.ts +17 -0
  59. package/dist/types/components/plugins/@antd/items/InputRender.d.ts +17 -0
  60. package/dist/types/components/plugins/@antd/items/ListRender.d.ts +11 -0
  61. package/dist/types/components/plugins/@antd/items/PageHeaderRender.d.ts +8 -0
  62. package/dist/types/components/plugins/@antd/items/RowRender.d.ts +13 -0
  63. package/dist/types/components/plugins/@antd/items/SelectRender.d.ts +18 -0
  64. package/dist/types/components/plugins/@antd/items/SpaceRender.d.ts +10 -0
  65. package/dist/types/components/plugins/@antd/items/SwitchRender.d.ts +14 -0
  66. package/dist/types/components/plugins/@antd/items/TableRender.d.ts +12 -0
  67. package/dist/types/components/plugins/@antd/items/TextRender.d.ts +9 -0
  68. package/dist/types/components/plugins/@antd/items/index.d.ts +19 -0
  69. package/dist/types/components/typing.d.ts +80 -0
  70. package/dist/types/components/utils.d.ts +9 -0
  71. package/dist/types/example.d.ts +2 -0
  72. package/dist/types/index.d.ts +1 -0
  73. package/dist/umd/css/bi-sdk.css +1 -0
  74. package/dist/umd/js/bi-sdk.umd.min.js +795 -0
  75. package/dist/umd/js/bi-sdk.umd.min.js.LICENSE.txt +9 -0
  76. package/package.json +52 -0
  77. package/src/components/PageDesigner.tsx +509 -0
  78. package/src/components/context/DesignerContext.tsx +71 -0
  79. package/src/components/context/EnvContext.tsx +42 -0
  80. package/src/components/dnd/DropContainer.tsx +474 -0
  81. package/src/components/example.ts +577 -0
  82. package/src/components/hooks/datasource.ts +23 -0
  83. package/src/components/hooks/useDeepCompareEffect.ts +12 -0
  84. package/src/components/icon/IconFont.tsx +16 -0
  85. package/src/components/index.ts +29 -0
  86. package/src/components/layout/PageCanvas.tsx +145 -0
  87. package/src/components/layout/PageItem.tsx +182 -0
  88. package/src/components/panel/AiPanel.tsx +116 -0
  89. package/src/components/panel/CascadePanel.tsx +163 -0
  90. package/src/components/panel/ChatInput.tsx +550 -0
  91. package/src/components/panel/CodePanel.tsx +48 -0
  92. package/src/components/panel/ComponentPanel.tsx +119 -0
  93. package/src/components/panel/DatasourcePanel.tsx +419 -0
  94. package/src/components/panel/LayerPanel.tsx +238 -0
  95. package/src/components/panel/PaneHeader.tsx +34 -0
  96. package/src/components/panel/PropertiesPanel.tsx +394 -0
  97. package/src/components/panel/ScriptPanel.tsx +175 -0
  98. package/src/components/panel/VariablesPanel.tsx +153 -0
  99. package/src/components/panel/index.ts +9 -0
  100. package/src/components/plugins/@antd/index.ts +445 -0
  101. package/src/components/plugins/@antd/item-props/ButtonProps.tsx +91 -0
  102. package/src/components/plugins/@antd/item-props/CapsuleProps.tsx +102 -0
  103. package/src/components/plugins/@antd/item-props/CardProps.tsx +58 -0
  104. package/src/components/plugins/@antd/item-props/CheckboxProps.tsx +75 -0
  105. package/src/components/plugins/@antd/item-props/ColProps.tsx +43 -0
  106. package/src/components/plugins/@antd/item-props/DatePickerProps.tsx +72 -0
  107. package/src/components/plugins/@antd/item-props/EchartsProps.tsx +35 -0
  108. package/src/components/plugins/@antd/item-props/HtmlProps.tsx +61 -0
  109. package/src/components/plugins/@antd/item-props/ImageProps.tsx +43 -0
  110. package/src/components/plugins/@antd/item-props/InputNumberProps.tsx +18 -0
  111. package/src/components/plugins/@antd/item-props/InputProps.tsx +89 -0
  112. package/src/components/plugins/@antd/item-props/ListProps.tsx +69 -0
  113. package/src/components/plugins/@antd/item-props/PageHeaderProps.tsx +20 -0
  114. package/src/components/plugins/@antd/item-props/RowProps.tsx +21 -0
  115. package/src/components/plugins/@antd/item-props/SelectProps.tsx +136 -0
  116. package/src/components/plugins/@antd/item-props/SpaceProps.tsx +52 -0
  117. package/src/components/plugins/@antd/item-props/SwitchProps.tsx +17 -0
  118. package/src/components/plugins/@antd/item-props/TableProps.tsx +200 -0
  119. package/src/components/plugins/@antd/item-props/TextProps.tsx +41 -0
  120. package/src/components/plugins/@antd/item-props/index.ts +20 -0
  121. package/src/components/plugins/@antd/item-props/types.ts +6 -0
  122. package/src/components/plugins/@antd/items/ButtonRender.tsx +63 -0
  123. package/src/components/plugins/@antd/items/CapsuleRender.tsx +49 -0
  124. package/src/components/plugins/@antd/items/CardRender.tsx +119 -0
  125. package/src/components/plugins/@antd/items/CheckboxRender.tsx +56 -0
  126. package/src/components/plugins/@antd/items/ColRender.tsx +78 -0
  127. package/src/components/plugins/@antd/items/DatePickerRender.tsx +117 -0
  128. package/src/components/plugins/@antd/items/EchartsRender.tsx +98 -0
  129. package/src/components/plugins/@antd/items/HtmlRender.tsx +74 -0
  130. package/src/components/plugins/@antd/items/ImageRender.tsx +37 -0
  131. package/src/components/plugins/@antd/items/InputNumberRender.tsx +57 -0
  132. package/src/components/plugins/@antd/items/InputRender.tsx +75 -0
  133. package/src/components/plugins/@antd/items/ListRender.tsx +227 -0
  134. package/src/components/plugins/@antd/items/PageHeaderRender.tsx +74 -0
  135. package/src/components/plugins/@antd/items/RowRender.tsx +47 -0
  136. package/src/components/plugins/@antd/items/SelectRender.tsx +53 -0
  137. package/src/components/plugins/@antd/items/SpaceRender.tsx +54 -0
  138. package/src/components/plugins/@antd/items/SwitchRender.tsx +52 -0
  139. package/src/components/plugins/@antd/items/TableRender.tsx +99 -0
  140. package/src/components/plugins/@antd/items/TextRender.tsx +25 -0
  141. package/src/components/plugins/@antd/items/index.ts +20 -0
  142. package/src/components/styles.css +12 -0
  143. package/src/components/typing.ts +80 -0
  144. package/src/components/utils.ts +37 -0
  145. package/src/example.tsx +136 -0
  146. package/src/index.tsx +17 -0
@@ -0,0 +1,419 @@
1
+ import {
2
+ CaretDownOutlined,
3
+ DeleteOutlined,
4
+ EditOutlined,
5
+ PlusOutlined,
6
+ } from "@ant-design/icons";
7
+ import Editor from "@monaco-editor/react";
8
+ import {
9
+ Button,
10
+ Dropdown,
11
+ Form,
12
+ Input,
13
+ Modal,
14
+ Popconfirm,
15
+ Radio,
16
+ Space,
17
+ Table,
18
+ } from "antd";
19
+ import React, { useContext, useMemo, useState } from "react";
20
+ import styled from "styled-components";
21
+ import { DesignerContext } from "../context/DesignerContext";
22
+ import { IconFont } from "../icon/IconFont";
23
+ import { PaneHeader } from "./PaneHeader";
24
+ import { uuid } from "../utils";
25
+ import { ApiType, SqlType } from "../typing";
26
+
27
+ const Root = styled.div`
28
+ display: flex;
29
+ flex-direction: column;
30
+ height: 100%;
31
+ .body {
32
+ flex: 1 1 auto;
33
+ display: flex;
34
+ flex-direction: column;
35
+ gap: 12px;
36
+ padding: 12px;
37
+ overflow: auto;
38
+ }
39
+ ul,
40
+ li {
41
+ list-style: none;
42
+ padding: 0;
43
+ margin: 0;
44
+ }
45
+ li {
46
+ display: flex;
47
+ align-items: center;
48
+ justify-content: space-between;
49
+ padding: 8px;
50
+ border-bottom: 1px dotted #d9d9d9;
51
+ }
52
+ li > div:first-child {
53
+ flex: 1 1 auto;
54
+ white-space: nowrap;
55
+ overflow: hidden;
56
+ text-overflow: ellipsis;
57
+ }
58
+ li:last-child {
59
+ border-bottom: none;
60
+ }
61
+ .margin-bottom-0 {
62
+ margin-bottom: 0;
63
+ }
64
+ `;
65
+
66
+ export const DatasourcePanel: React.FC = () => {
67
+ const { schema, setSchema } = useContext(DesignerContext);
68
+
69
+ const [apiVisible, setApiVisible] = useState(false);
70
+ const [sqlVisible, setSqlVisible] = useState(false);
71
+ const [editIndex, setEditIndex] = useState<number>(-1);
72
+ const [apiForm, setApiForm] = useState<ApiType>({
73
+ id: uuid(),
74
+ type: "api",
75
+ name: "",
76
+ url: "",
77
+ method: "GET",
78
+ headers: [] as any[],
79
+ formData: [] as any[],
80
+ body: "",
81
+ });
82
+ const [sqlForm, setSqlForm] = useState<SqlType>({
83
+ id: uuid(),
84
+ type: "sql",
85
+ name: "",
86
+ query: "",
87
+ });
88
+ const list = useMemo(() => schema.datasources, [schema.datasources]);
89
+
90
+ const onUpdateDatasources = (list: any[]) => {
91
+ setSchema({ ...schema, datasources: list });
92
+ };
93
+
94
+ const apiColumns = [
95
+ {
96
+ title: "键",
97
+ dataIndex: "name",
98
+ render: (_: any, r: any, index: number) => (
99
+ <Input
100
+ size="small"
101
+ value={r.name}
102
+ onChange={(e) => {
103
+ const headers = [...apiForm.headers];
104
+ headers[index] = { ...headers[index], name: e.target.value };
105
+ setApiForm({ ...apiForm, headers });
106
+ }}
107
+ />
108
+ ),
109
+ },
110
+ {
111
+ title: "值",
112
+ dataIndex: "value",
113
+ render: (_: any, r: any, index: number) => (
114
+ <Input
115
+ size="small"
116
+ value={r.value}
117
+ onChange={(e) => {
118
+ const headers = [...apiForm.headers];
119
+ headers[index] = { ...headers[index], value: e.target.value };
120
+ setApiForm({ ...apiForm, headers });
121
+ }}
122
+ />
123
+ ),
124
+ },
125
+ {
126
+ title: "操作",
127
+ width: 50,
128
+ align: "center" as const,
129
+ render: (_: any, r: any, index: number) => (
130
+ <Space>
131
+ <a
132
+ onClick={() => {
133
+ const headers = [...apiForm.headers];
134
+ headers.splice(index, 1);
135
+ setApiForm({ ...apiForm, headers });
136
+ }}
137
+ >
138
+ <DeleteOutlined />
139
+ </a>
140
+ </Space>
141
+ ),
142
+ },
143
+ ];
144
+ const apiFormAdd = () =>
145
+ setApiForm({
146
+ id: uuid(),
147
+ type: "api",
148
+ name: "",
149
+ url: "",
150
+ method: "GET",
151
+ headers: [],
152
+ formData: [],
153
+ body: "",
154
+ });
155
+ const sqlFormAdd = () =>
156
+ setSqlForm({ id: uuid(), type: "sql", name: "", query: "" });
157
+ const handleAddApi = () => {
158
+ setEditIndex(-1);
159
+ apiFormAdd();
160
+ setApiVisible(true);
161
+ };
162
+ const handleAddSql = () => {
163
+ setEditIndex(-1);
164
+ sqlFormAdd();
165
+ setSqlVisible(true);
166
+ };
167
+ const handleEdit = (item: any, index: number) => {
168
+ setEditIndex(index);
169
+ if (item.type === "api") {
170
+ setApiForm({ ...item });
171
+ setApiVisible(true);
172
+ } else {
173
+ setSqlForm({ ...item });
174
+ setSqlVisible(true);
175
+ }
176
+ };
177
+ const handleDelete = (index: number) => {
178
+ const next = [...list];
179
+ next.splice(index, 1);
180
+ onUpdateDatasources && onUpdateDatasources(next);
181
+ };
182
+ const handleApiOk = () => {
183
+ if (!apiForm.name || !apiForm.url) return;
184
+ const next = [...list];
185
+ if (editIndex === -1) next.push(apiForm);
186
+ else next[editIndex] = apiForm;
187
+ onUpdateDatasources && onUpdateDatasources(next);
188
+ setApiVisible(false);
189
+ };
190
+ const handleSqlOk = () => {
191
+ if (!sqlForm.name || !sqlForm.query) return;
192
+ const next = [...list];
193
+ if (editIndex === -1) next.push(sqlForm);
194
+ else next[editIndex] = sqlForm;
195
+ onUpdateDatasources && onUpdateDatasources(next);
196
+ setSqlVisible(false);
197
+ };
198
+ return (
199
+ <Root className="datasource-panel">
200
+ <PaneHeader
201
+ title="数据源"
202
+ extra={
203
+ <Space>
204
+ <Dropdown
205
+ menu={{
206
+ onClick: ({ key }) => {
207
+ key === "api" ? handleAddApi() : handleAddSql();
208
+ },
209
+ items: [
210
+ { key: "api", label: <a>API接口</a> },
211
+ { key: "sql", label: <a>SQL查询</a> },
212
+ ],
213
+ }}
214
+ placement="bottom"
215
+ >
216
+ <a className="toolbar">
217
+ <PlusOutlined />
218
+ <CaretDownOutlined
219
+ style={{ fontSize: 8, verticalAlign: "sub" }}
220
+ />
221
+ </a>
222
+ </Dropdown>
223
+ </Space>
224
+ }
225
+ />
226
+ <div className="body">
227
+ <ul>
228
+ {list.map((item, index) => (
229
+ <li key={item.id}>
230
+ <div title={item.name}>
231
+ <IconFont type="icon-drag" /> {item.name}
232
+ </div>
233
+ <Space>
234
+ <a onClick={() => handleEdit(item, index)}>
235
+ <EditOutlined />
236
+ </a>
237
+ <Popconfirm
238
+ title="确认删除吗?"
239
+ okText="确认"
240
+ cancelText="取消"
241
+ onConfirm={() => handleDelete(index)}
242
+ >
243
+ <a>
244
+ <DeleteOutlined />
245
+ </a>
246
+ </Popconfirm>
247
+ </Space>
248
+ </li>
249
+ ))}
250
+ </ul>
251
+ </div>
252
+ <Modal
253
+ title="添加API接口"
254
+ open={apiVisible}
255
+ width={600}
256
+ styles={{
257
+ body: { maxHeight: "calc(100vh - 250px)", overflow: "auto" },
258
+ }}
259
+ onCancel={() => setApiVisible(false)}
260
+ footer={
261
+ <Space>
262
+ <Button type="primary" onClick={handleApiOk}>
263
+ 确定
264
+ </Button>
265
+ <Button onClick={() => setApiVisible(false)}>取消</Button>
266
+ </Space>
267
+ }
268
+ >
269
+ <Form labelCol={{ span: 24 }} wrapperCol={{ span: 24 }}>
270
+ <Form.Item label="接口名称" required>
271
+ <Input
272
+ value={apiForm.name}
273
+ onChange={(e) => setApiForm({ ...apiForm, name: e.target.value })}
274
+ />
275
+ </Form.Item>
276
+ <Form.Item label="接口URL" required>
277
+ <Input
278
+ value={apiForm.url}
279
+ onChange={(e) => setApiForm({ ...apiForm, url: e.target.value })}
280
+ />
281
+ </Form.Item>
282
+ <Form.Item label="请求方法">
283
+ <Radio.Group
284
+ value={apiForm.method}
285
+ onChange={(e) =>
286
+ setApiForm({ ...apiForm, method: e.target.value })
287
+ }
288
+ >
289
+ <Radio.Button value="GET">GET</Radio.Button>
290
+ <Radio.Button value="POST">POST</Radio.Button>
291
+ <Radio.Button value="PUT">PUT</Radio.Button>
292
+ <Radio.Button value="DELETE">DELETE</Radio.Button>
293
+ </Radio.Group>
294
+ </Form.Item>
295
+ <label
296
+ style={{ display: "block", color: "#000000d9", padding: "8px 0" }}
297
+ >
298
+ 请求头
299
+ </label>
300
+ <Table
301
+ columns={apiColumns as any}
302
+ dataSource={apiForm.headers}
303
+ pagination={false}
304
+ locale={{ emptyText: "暂无数据" }}
305
+ size="small"
306
+ bordered
307
+ rowKey={(_, i) => String(i)}
308
+ />
309
+ <Button
310
+ size="small"
311
+ block
312
+ onClick={() =>
313
+ setApiForm({
314
+ ...apiForm,
315
+ headers: [...apiForm.headers, { name: "", value: "" }],
316
+ })
317
+ }
318
+ >
319
+ 添加
320
+ </Button>
321
+ <label
322
+ style={{ display: "block", color: "#000000d9", padding: "8px 0" }}
323
+ >
324
+ 表单数据
325
+ </label>
326
+ <Table
327
+ columns={apiColumns as any}
328
+ dataSource={apiForm.formData}
329
+ pagination={false}
330
+ locale={{ emptyText: "暂无数据" }}
331
+ size="small"
332
+ bordered
333
+ rowKey={(_, i) => `f-${i}`}
334
+ />
335
+ <Button
336
+ size="small"
337
+ block
338
+ onClick={() =>
339
+ setApiForm({
340
+ ...apiForm,
341
+ formData: [...apiForm.formData, { name: "", value: "" }],
342
+ })
343
+ }
344
+ >
345
+ 添加
346
+ </Button>
347
+ <Form.Item label="请求体">
348
+ <div
349
+ style={{
350
+ border: `1px solid var(--ant-color-border)`,
351
+ borderRadius: "var(--ant-border-radius)",
352
+ padding: 1,
353
+ }}
354
+ >
355
+ <Editor
356
+ height="300px"
357
+ defaultLanguage="json"
358
+ value={apiForm.body}
359
+ onChange={(v) => setApiForm({ ...apiForm, body: v || "" })}
360
+ options={{
361
+ minimap: { enabled: false },
362
+ scrollBeyondLastLine: false,
363
+ tabSize: 2,
364
+ }}
365
+ />
366
+ </div>
367
+ </Form.Item>
368
+ </Form>
369
+ </Modal>
370
+ <Modal
371
+ title="添加SQL查询"
372
+ open={sqlVisible}
373
+ width={600}
374
+ styles={{
375
+ body: { maxHeight: "calc(100vh - 250px)", overflow: "auto" },
376
+ }}
377
+ onCancel={() => setSqlVisible(false)}
378
+ footer={
379
+ <Space>
380
+ <Button type="primary" onClick={handleSqlOk}>
381
+ 确定
382
+ </Button>
383
+ <Button onClick={() => setSqlVisible(false)}>取消</Button>
384
+ </Space>
385
+ }
386
+ >
387
+ <Form layout="vertical">
388
+ <Form.Item label="查询名称" required>
389
+ <Input
390
+ value={sqlForm.name}
391
+ onChange={(e) => setSqlForm({ ...sqlForm, name: e.target.value })}
392
+ />
393
+ </Form.Item>
394
+ <Form.Item label="查询语句" required>
395
+ <div
396
+ style={{
397
+ border: `1px solid var(--ant-color-border)`,
398
+ borderRadius: "var(--ant-border-radius)",
399
+ padding: 1,
400
+ }}
401
+ >
402
+ <Editor
403
+ height="300px"
404
+ defaultLanguage="sql"
405
+ value={sqlForm.query}
406
+ onChange={(v) => setSqlForm({ ...sqlForm, query: v || "" })}
407
+ options={{
408
+ minimap: { enabled: false },
409
+ scrollBeyondLastLine: false,
410
+ tabSize: 2,
411
+ }}
412
+ />
413
+ </div>
414
+ </Form.Item>
415
+ </Form>
416
+ </Modal>
417
+ </Root>
418
+ );
419
+ };
@@ -0,0 +1,238 @@
1
+ import { MinusSquareOutlined, PlusSquareOutlined } from "@ant-design/icons";
2
+ import { Space, Tooltip, Tree } from "antd";
3
+ import React, { useContext, useMemo, useState } from "react";
4
+ import styled from "styled-components";
5
+ import { DesignerContext } from "../context/DesignerContext";
6
+ import { uuid } from "../utils";
7
+ import { PaneHeader } from "./PaneHeader";
8
+
9
+ const Root = styled.div`
10
+ display: flex;
11
+ flex-direction: column;
12
+ height: 100%;
13
+ .body {
14
+ flex: 1 1 auto;
15
+ display: flex;
16
+ flex-direction: column;
17
+ gap: 12px;
18
+ padding: 12px;
19
+ overflow: auto;
20
+ }
21
+ `;
22
+
23
+ const DraggableTree = styled(Tree)`
24
+ .ant-tree-draggable-icon {
25
+ display: none;
26
+ }
27
+
28
+ .ant-tree-title {
29
+ white-space: nowrap;
30
+ overflow: hidden;
31
+ text-overflow: ellipsis;
32
+ }
33
+ `;
34
+
35
+ export const LayerPanel: React.FC = () => {
36
+ const {
37
+ schema,
38
+ setSchema: onSchemaChange,
39
+ selectedItem,
40
+ setSelectedItem: onSelect,
41
+ plugins,
42
+ } = useContext(DesignerContext);
43
+ const [expandedKeys, setExpandedKeys] = useState<string[]>([]);
44
+ const selectedKeys = useMemo(
45
+ () => (selectedItem ? [selectedItem.id!] : []),
46
+ [selectedItem]
47
+ );
48
+ const realItems = useMemo(() => {
49
+ const compute = (list: any[] = []) => {
50
+ return list.map((item) => {
51
+ const { id, type, children } = item;
52
+ let c: any = undefined;
53
+ if (Array.isArray(children)) {
54
+ c = compute(children);
55
+ } else if (typeof children === "object" && children) {
56
+ c = [];
57
+ Object.keys(children).forEach((k) => {
58
+ if (!Array.isArray(children[k])) return;
59
+ c.push({
60
+ key: uuid(),
61
+ type: "slot",
62
+ slot: k,
63
+ origin: children,
64
+ children: compute(children[k]),
65
+ });
66
+ });
67
+ }
68
+ return { key: id, title: type, item, type, children: c };
69
+ });
70
+ };
71
+ return compute(schema.items);
72
+ }, [schema]);
73
+ const formatType = (type: string, slot?: string) => {
74
+ if (type === "slot") return "插槽-" + slot;
75
+ return plugins.find((i) => i.key === type)?.label || type;
76
+ };
77
+ const allowDrop = (info: any) => {
78
+ const dropNode = info.node;
79
+ const dragNode = info.dragNode;
80
+ if (dragNode.dataRef.type === "slot") return false;
81
+ if (
82
+ !info.dropToGap &&
83
+ !["b-row", "b-col", "b-card", "slot"].includes(dropNode.dataRef.type)
84
+ )
85
+ return false;
86
+ if (dragNode.dataRef.type === "b-col") {
87
+ if (!info.dropToGap) {
88
+ return dropNode.dataRef.type === "b-row";
89
+ } else {
90
+ return dropNode.dataRef.type === "b-col";
91
+ }
92
+ }
93
+ if (dropNode.dataRef.type === "b-col") {
94
+ if (info.dropToGap) {
95
+ return dragNode.dataRef.type === "b-col";
96
+ }
97
+ }
98
+ if (dropNode.dataRef.type === "b-row") {
99
+ if (!info.dropToGap) return dragNode.dataRef.type === "b-col";
100
+ }
101
+ return true;
102
+ };
103
+ const onDrop = (info: any) => {
104
+ if (!allowDrop(info)) return;
105
+ const dropKey = info.node.key;
106
+ const dragKey = info.dragNode.key;
107
+ const dropPos = info.node.pos.split("-");
108
+ const dropPosition =
109
+ info.dropPosition - Number(dropPos[dropPos.length - 1]);
110
+ const loop = (data: any[], key: string, callback: Function) => {
111
+ data.forEach((item, index, arr) => {
112
+ if (item.id === key) {
113
+ item.children = item.children || [];
114
+ if (item.type === "slot") {
115
+ return callback(item, index, arr, item.children[item.slot]);
116
+ }
117
+ return callback(item, index, arr, item.children);
118
+ }
119
+ if (Array.isArray(item.children)) {
120
+ return loop(item.children, key, callback);
121
+ } else if (typeof item.children === "object") {
122
+ for (let k in item.children) {
123
+ if (Array.isArray(item.children[k])) {
124
+ loop(item.children[k], key, callback);
125
+ }
126
+ }
127
+ }
128
+ });
129
+ };
130
+ const data = schema.items;
131
+ let dragObj: any;
132
+ loop(data, dragKey, (item: any, index: number, arr: any[]) => {
133
+ arr.splice(index, 1);
134
+ dragObj = item;
135
+ });
136
+ if (!info.dropToGap) {
137
+ if (info.node.dataRef.type === "slot") {
138
+ const { slot, origin } = info.node.dataRef;
139
+ console.log(slot, JSON.stringify(origin));
140
+ origin[slot] = origin[slot] || [];
141
+ origin[slot].push(dragObj);
142
+ }
143
+ loop(data, dropKey, (item: any) => {
144
+ item.children = item.children || [];
145
+ item.children.push(dragObj);
146
+ });
147
+ } else if (
148
+ (info.node.children || []).length > 0 &&
149
+ info.node.expanded &&
150
+ dropPosition === 1
151
+ ) {
152
+ loop(data, dropKey, (item: any, index: number, arr: any[]) => {
153
+ item.children = item.children || [];
154
+ item.children.unshift(dragObj);
155
+ });
156
+ } else {
157
+ let ar: any[] = [];
158
+ let i = 0;
159
+ loop(data, dropKey, (item: any, index: number, arr: any[]) => {
160
+ ar = arr;
161
+ i = index;
162
+ });
163
+ if (dropPosition === -1) {
164
+ ar.splice(i, 0, dragObj);
165
+ } else {
166
+ ar.splice(i + 1, 0, dragObj);
167
+ }
168
+ }
169
+ onSchemaChange && onSchemaChange({ ...schema, items: data });
170
+ };
171
+ const expandAll = () => {
172
+ const keys: string[] = [];
173
+ const compute = (list: any[] = []) => {
174
+ list.forEach((item) => {
175
+ keys.push(item.id);
176
+ if (item.children?.length) compute(item.children);
177
+ });
178
+ };
179
+ compute(schema.items);
180
+ setExpandedKeys(keys);
181
+ };
182
+ const collapseAll = () => setExpandedKeys([]);
183
+
184
+ const treeData = useMemo(() => {
185
+ const computeTreeData = (list: any[] = []): any[] => {
186
+ return list.map((item) => ({
187
+ key: item.key,
188
+ title: <span>{formatType(item.type, (item as any).slot)}</span>,
189
+ children: item.children ? computeTreeData(item.children) : undefined,
190
+ dataRef: item,
191
+ }));
192
+ };
193
+ return computeTreeData(realItems);
194
+ }, [realItems]);
195
+
196
+ return (
197
+ <Root className="layer-panel">
198
+ <PaneHeader
199
+ title="图层"
200
+ extra={
201
+ <Space>
202
+ <Tooltip title="全部展开">
203
+ <a className="toolbar" onClick={expandAll}>
204
+ <PlusSquareOutlined />
205
+ </a>
206
+ </Tooltip>
207
+ <Tooltip title="全部收起">
208
+ <a className="toolbar" onClick={collapseAll}>
209
+ <MinusSquareOutlined />
210
+ </a>
211
+ </Tooltip>
212
+ </Space>
213
+ }
214
+ />
215
+ <div className="body">
216
+ <DraggableTree
217
+ draggable={{
218
+ icon: false,
219
+ nodeDraggable(node: any) {
220
+ return false; // node.dataRef.type !== "slot";
221
+ },
222
+ }}
223
+ showIcon={false}
224
+ showLine={{ showLeafIcon: false }}
225
+ treeData={treeData}
226
+ selectedKeys={selectedKeys}
227
+ expandedKeys={expandedKeys}
228
+ onSelect={(_, info: any) => {
229
+ if (info.node.dataRef.type === "slot") return;
230
+ onSelect && onSelect(info.node.dataRef.item);
231
+ }}
232
+ onDrop={onDrop}
233
+ onExpand={(keys) => setExpandedKeys(keys as string[])}
234
+ />
235
+ </div>
236
+ </Root>
237
+ );
238
+ };
@@ -0,0 +1,34 @@
1
+ import React from 'react'
2
+ import styled from 'styled-components'
3
+
4
+ export type PaneHeaderProps = {
5
+ title?: string
6
+ extra?: React.ReactNode
7
+ }
8
+
9
+ const Header = styled.div`
10
+ width: 100%;
11
+ padding: 0 12px;
12
+ border-bottom: solid 1px #e8e8e8;
13
+ background: #ffffff;
14
+ height: 40px;
15
+ display: flex;
16
+ align-items: center;
17
+ justify-content: space-between;
18
+ .title {
19
+ font-size: 14px;
20
+ line-height: 40px;
21
+ }
22
+ .extra {
23
+ line-height: 32px;
24
+ }
25
+ `
26
+
27
+ export const PaneHeader: React.FC<PaneHeaderProps> = ({ title = '', extra }) => {
28
+ return (
29
+ <Header className="pane-header">
30
+ <span className="title">{title}</span>
31
+ <div className="extra">{extra}</div>
32
+ </Header>
33
+ )
34
+ }