bi-sdk-react 0.0.50 → 0.0.52

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 (37) hide show
  1. package/dist/es/js/bi-sdk.es.js +123 -34
  2. package/dist/types/components/context/PageContext.d.ts +10 -0
  3. package/dist/types/components/hooks/event.d.ts +4 -0
  4. package/dist/types/components/hooks/method.d.ts +4 -0
  5. package/dist/types/components/layout/PageItem.d.ts +1 -0
  6. package/dist/types/components/panel/EventPanel.d.ts +2 -0
  7. package/dist/types/components/plugins/@antd/index.d.ts +2 -0
  8. package/dist/types/components/plugins/@antd/item-props/DrawerProps.d.ts +20 -0
  9. package/dist/types/components/plugins/@antd/item-props/ModalProps.d.ts +18 -0
  10. package/dist/types/components/plugins/@antd/item-props/index.d.ts +2 -0
  11. package/dist/types/components/plugins/@antd/items/DrawerRender.d.ts +19 -0
  12. package/dist/types/components/plugins/@antd/items/EchartsRender.d.ts +2 -2
  13. package/dist/types/components/plugins/@antd/items/ModalRender.d.ts +17 -0
  14. package/dist/types/components/plugins/@antd/items/index.d.ts +2 -0
  15. package/dist/types/components/typing.d.ts +13 -1
  16. package/dist/umd/js/bi-sdk.umd.min.js +124 -35
  17. package/package.json +1 -1
  18. package/src/components/PageDesigner.tsx +57 -41
  19. package/src/components/context/PageContext.tsx +44 -1
  20. package/src/components/dnd/DropContainer.tsx +33 -0
  21. package/src/components/hooks/event.ts +68 -0
  22. package/src/components/hooks/method.ts +13 -0
  23. package/src/components/icon/IconFont.tsx +1 -1
  24. package/src/components/layout/PageItem.tsx +17 -2
  25. package/src/components/panel/EventPanel.tsx +186 -0
  26. package/src/components/panel/LayerPanel.tsx +7 -6
  27. package/src/components/plugins/@antd/index.ts +65 -1
  28. package/src/components/plugins/@antd/item-props/DrawerProps.tsx +174 -0
  29. package/src/components/plugins/@antd/item-props/ModalProps.tsx +153 -0
  30. package/src/components/plugins/@antd/item-props/index.ts +2 -0
  31. package/src/components/plugins/@antd/items/ButtonRender.tsx +3 -0
  32. package/src/components/plugins/@antd/items/DrawerRender.tsx +175 -0
  33. package/src/components/plugins/@antd/items/EchartsRender.tsx +30 -3
  34. package/src/components/plugins/@antd/items/ModalRender.tsx +158 -0
  35. package/src/components/plugins/@antd/items/index.ts +2 -1
  36. package/src/components/typing.ts +13 -1
  37. package/src/example.tsx +2 -49
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bi-sdk-react",
3
- "version": "0.0.50",
3
+ "version": "0.0.52",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "dist/umd/js/bi-sdk.umd.min.js",
@@ -44,6 +44,7 @@ import {
44
44
  SchemaItemType,
45
45
  } from "./typing";
46
46
  import { uuid } from "./utils";
47
+ import { EventPanel } from "./panel/EventPanel";
47
48
 
48
49
  export type PageDesignerProps = {
49
50
  pageId: string;
@@ -267,7 +268,7 @@ export const PageDesigner = React.forwardRef<any, PageDesignerProps>(
267
268
  | "dataset"
268
269
  >("component");
269
270
  const [rightPanelActiveKey, setRightPanelActiveKey] = useState<
270
- "ai" | "props" | "cascade"
271
+ "ai" | "props" | "cascade" | "events"
271
272
  >(fetch?.ai ? "ai" : "props");
272
273
  const [showLeft, setShowLeft] = useState(true);
273
274
  const [showRight, setShowRight] = useState(true);
@@ -467,6 +468,11 @@ export const PageDesigner = React.forwardRef<any, PageDesignerProps>(
467
468
  return rightPanelActiveKey;
468
469
  }, [selectedItem, rightPanelActiveKey]);
469
470
 
471
+
472
+ const selectedPlugin: PluginType | undefined = useMemo(() => {
473
+ return (plugins || []).find((p) => p.key === selectedItem?.type);
474
+ }, [plugins, selectedItem?.type]);
475
+
470
476
  return (
471
477
  <PageProvider
472
478
  pageId={pageId}
@@ -593,47 +599,47 @@ export const PageDesigner = React.forwardRef<any, PageDesignerProps>(
593
599
  }}
594
600
  className="left-pane-tabs"
595
601
  >
596
- <Radio.Button value="component">
597
- <Tooltip title="组件" placement="right">
602
+ <Tooltip title="组件" placement="right">
603
+ <Radio.Button value="component">
598
604
  <IconFont type="icon-puzzle" />
599
- </Tooltip>
600
- </Radio.Button>
601
- <Radio.Button value="layer">
602
- <Tooltip title="图层" placement="right">
605
+ </Radio.Button>
606
+ </Tooltip>
607
+ <Tooltip title="图层" placement="right">
608
+ <Radio.Button value="layer">
603
609
  <IconFont type="icon-outline" />
604
- </Tooltip>
605
- </Radio.Button>
610
+ </Radio.Button>
611
+ </Tooltip>
606
612
  {!!datasetPanel && (
607
- <Radio.Button value="dataset">
608
- <Tooltip title="数据集" placement="right">
613
+ <Tooltip title="数据集" placement="right">
614
+ <Radio.Button value="dataset">
609
615
  <IconFont type="icon-dataset" />
610
- </Tooltip>
611
- </Radio.Button>
616
+ </Radio.Button>
617
+ </Tooltip>
612
618
  )}
613
619
  {datasourceEnable && (
614
- <Radio.Button value="datasource" title="数据源">
615
- <Tooltip title="数据源" placement="right">
620
+ <Tooltip title="数据源" placement="right">
621
+ <Radio.Button value="datasource" title="数据源">
616
622
  <IconFont type="icon-datasource" />
617
- </Tooltip>
618
- </Radio.Button>
623
+ </Radio.Button>
624
+ </Tooltip>
619
625
  )}
620
626
  {scriptEnable && (
621
- <Radio.Button value="script">
622
- <Tooltip title="脚本" placement="right">
627
+ <Tooltip title="脚本" placement="right">
628
+ <Radio.Button value="script">
623
629
  <IconFont type="icon-js" />
624
- </Tooltip>
625
- </Radio.Button>
630
+ </Radio.Button>
631
+ </Tooltip>
626
632
  )}
627
- <Radio.Button value="env">
628
- <Tooltip title="环境变量" placement="right">
633
+ <Tooltip title="环境变量" placement="right">
634
+ <Radio.Button value="env">
629
635
  <IconFont type="icon-variable" />
630
- </Tooltip>
631
- </Radio.Button>
632
- <Radio.Button value="code">
633
- <Tooltip title="源码" placement="right">
636
+ </Radio.Button>
637
+ </Tooltip>
638
+ <Tooltip title="源码" placement="right">
639
+ <Radio.Button value="code">
634
640
  <IconFont type="icon-json" />
635
- </Tooltip>
636
- </Radio.Button>
641
+ </Radio.Button>
642
+ </Tooltip>
637
643
  </Radio.Group>
638
644
  </div>
639
645
  <div
@@ -733,6 +739,9 @@ export const PageDesigner = React.forwardRef<any, PageDesignerProps>(
733
739
  {rightActiveKey === "cascade" && selectedItem?.cascadeIds && (
734
740
  <CascadePanel />
735
741
  )}
742
+ {rightActiveKey === "events" && selectedPlugin?.events && (
743
+ <EventPanel />
744
+ )}
736
745
  </div>
737
746
  <div
738
747
  style={{
@@ -757,23 +766,30 @@ export const PageDesigner = React.forwardRef<any, PageDesignerProps>(
757
766
  className="right-pane-tabs"
758
767
  >
759
768
  {fetch?.ai && (
760
- <Radio.Button value="ai">
761
- <Tooltip title="智能助理" placement="right">
769
+ <Tooltip title="智能助理" placement="right">
770
+ <Radio.Button value="ai">
762
771
  <IconFont type="icon-assistant" />
763
- </Tooltip>
764
- </Radio.Button>
772
+ </Radio.Button>
773
+ </Tooltip>
765
774
  )}
766
- <Radio.Button value="props">
767
- <Tooltip title="属性" placement="right">
775
+ <Tooltip title="属性" placement="right">
776
+ <Radio.Button value="props">
768
777
  <IconFont type="icon-info" />
769
- </Tooltip>
770
- </Radio.Button>
778
+ </Radio.Button>
779
+ </Tooltip>
771
780
  {selectedItem?.cascadeIds && (
772
- <Radio.Button value="cascade">
773
- <Tooltip title="联动" placement="right">
781
+ <Tooltip title="联动" placement="right">
782
+ <Radio.Button value="cascade">
774
783
  <IconFont type="icon-cascade" />
775
- </Tooltip>
776
- </Radio.Button>
784
+ </Radio.Button>
785
+ </Tooltip>
786
+ )}
787
+ {selectedPlugin?.events && (
788
+ <Tooltip title="事件" placement="right">
789
+ <Radio.Button value="events">
790
+ <IconFont type="icon-thunderbolt" />
791
+ </Radio.Button>
792
+ </Tooltip>
777
793
  )}
778
794
  </Radio.Group>
779
795
  {/* <Popover
@@ -16,6 +16,9 @@ type InitCallbackParams = {
16
16
  callback: CallbackType;
17
17
  };
18
18
 
19
+ type MethodParams = { sourceId: string; arg?: any };
20
+ type MethodType = Record<string, (params?: MethodParams) => any>;
21
+
19
22
  type PageContextType = {
20
23
  pageId: string;
21
24
  designable: boolean;
@@ -42,6 +45,19 @@ type PageContextType = {
42
45
  refresh?: boolean,
43
46
  consume?: (item: Omit<SchemaItemType, "children">, data: any) => void,
44
47
  ) => void;
48
+ initMethod: ({
49
+ id,
50
+ method,
51
+ }: {
52
+ id: string;
53
+ method: MethodType;
54
+ }) => any;
55
+ handleMethod: (
56
+ item: SchemaItemType,
57
+ targetId: string,
58
+ methodName: string,
59
+ arg?: any,
60
+ ) => any;
45
61
  getVars: (id: string) => Record<string, any>;
46
62
  setVar: (item: SchemaItemType, key: string, value: any) => void;
47
63
  setItemData?: (id: string, data: any) => void;
@@ -75,6 +91,8 @@ export const PageContext = createContext<PageContextType>({
75
91
  setDeviceWidth: () => {},
76
92
  initCallback: () => {},
77
93
  handleCallback: () => {},
94
+ initMethod: () => {},
95
+ handleMethod: () => {},
78
96
  getVars: () => ({}),
79
97
  setVar: () => {},
80
98
  setItemData: () => {},
@@ -129,6 +147,30 @@ export const PageProvider: React.FC<PageProviderProps> = ({
129
147
 
130
148
  const [env, setEnv] = useState<EnvType>({ global: {}, local: {} });
131
149
  const [callbacks, setCallbacks] = useState<CallbacksType>({});
150
+ const [methods, setMethods] = useState<Record<string, MethodType>>({});
151
+
152
+ const initMethod = ({
153
+ id,
154
+ method,
155
+ }: {
156
+ id: string;
157
+ method: MethodType;
158
+ }) => {
159
+ setMethods((c) => ({ ...c, [id]: method }));
160
+ };
161
+
162
+ const handleMethod = (
163
+ item: SchemaItemType,
164
+ targetId: string,
165
+ methodName: string,
166
+ arg?: any,
167
+ ) => {
168
+ const method = methods[targetId][methodName];
169
+ if (typeof method === "function") {
170
+ return method({ sourceId: item.id!, arg });
171
+ }
172
+ return null;
173
+ };
132
174
 
133
175
  const initCallback = ({
134
176
  id,
@@ -173,7 +215,6 @@ export const PageProvider: React.FC<PageProviderProps> = ({
173
215
  });
174
216
  };
175
217
 
176
-
177
218
  useEffect(() => {
178
219
  const nextGlobal: Record<string, any> = {};
179
220
  (schema.variables || []).forEach((item) => {
@@ -207,6 +248,8 @@ export const PageProvider: React.FC<PageProviderProps> = ({
207
248
  setDeviceWidth: setDeviceWidth || (() => {}),
208
249
  initCallback,
209
250
  handleCallback,
251
+ initMethod,
252
+ handleMethod,
210
253
  getVars,
211
254
  setVar,
212
255
  setItemData,
@@ -4,6 +4,7 @@ import { PageItem, PageItemProps } from "../layout/PageItem";
4
4
  import { HtmlBaseProps, SchemaItemType } from "../typing";
5
5
  import styled from "styled-components";
6
6
  import { PageContext } from "../context/PageContext";
7
+ import { uuid } from "../utils";
7
8
 
8
9
  type DropContainerProps = {
9
10
  rootComponent?: React.ComponentType<any>;
@@ -441,6 +442,37 @@ export const DropContainer: React.FC<DropContainerProps> = ({
441
442
  return () => cleanup();
442
443
  }, []);
443
444
 
445
+ const onCopy = (item: SchemaItemType) => {
446
+ // 递归复制函数,确保所有子节点都有新的 ID
447
+ const cloneItem = (node: SchemaItemType): SchemaItemType => {
448
+ const newNode = { ...node, id: uuid() };
449
+
450
+ if (node.children) {
451
+ if (Array.isArray(node.children)) {
452
+ newNode.children = node.children.map(cloneItem);
453
+ } else {
454
+ const newChildren: Record<string, SchemaItemType[]> = {};
455
+ Object.keys(node.children).forEach((key) => {
456
+ newChildren[key] = (node.children as Record<string, SchemaItemType[]>)[
457
+ key
458
+ ].map(cloneItem);
459
+ });
460
+ newNode.children = newChildren;
461
+ }
462
+ }
463
+ return newNode;
464
+ };
465
+
466
+ const newItem = cloneItem(item);
467
+ const index = list.findIndex((i) => i.id === item.id);
468
+
469
+ if (index !== -1) {
470
+ const newList = [...list];
471
+ newList.splice(index + 1, 0, newItem);
472
+ onListChange?.(newList);
473
+ }
474
+ };
475
+
444
476
  // Determine classes
445
477
  const classes = [
446
478
  className,
@@ -483,6 +515,7 @@ export const DropContainer: React.FC<DropContainerProps> = ({
483
515
  parentList={memoList}
484
516
  onListChange={onListChange}
485
517
  index={index}
518
+ onCopy={onCopy}
486
519
  onDelete={() =>
487
520
  onListChange?.(memoList.filter((i: any) => i.id !== child.id))
488
521
  }
@@ -0,0 +1,68 @@
1
+ import { SchemaItemType } from "../typing";
2
+ import { useMethods } from "./method";
3
+
4
+ export const useEvent = (item: SchemaItemType) => {
5
+ const events = (item.events || []).reduce(
6
+ (acc, cur) => {
7
+ acc[cur.name] = cur.script;
8
+ return acc;
9
+ },
10
+ {} as Record<string, string>,
11
+ );
12
+
13
+ const { callMethod } = useMethods(item);
14
+
15
+ const handleEvent = (eventName: string, arg?: any) => {
16
+ const script = events[eventName];
17
+ if (script) {
18
+ if (script) {
19
+ try {
20
+ const safeEval = new Function(
21
+ "console",
22
+ "Math",
23
+ "Date",
24
+ "Array",
25
+ "Object",
26
+ "String",
27
+ "Number",
28
+ "Boolean",
29
+ "callMethod",
30
+ "param",
31
+ `
32
+ "use strict";
33
+ const window = undefined;
34
+ const document = undefined;
35
+ const global = undefined;
36
+ const process = undefined;
37
+ const require = undefined;
38
+ const module = undefined;
39
+ const exports = undefined;
40
+ ${script}
41
+ `,
42
+ );
43
+ return (safeEval as any)(
44
+ console,
45
+ Math,
46
+ Date,
47
+ Array,
48
+ Object,
49
+ String,
50
+ Number,
51
+ Boolean,
52
+ callMethod,
53
+ {
54
+ item,
55
+ sourceId: item.id,
56
+ arg,
57
+ },
58
+ );
59
+ } catch (evalError) {
60
+ console.error("点击事件脚本执行失败:", evalError);
61
+ return null;
62
+ }
63
+ }
64
+ }
65
+ };
66
+
67
+ return { handleEvent };
68
+ };
@@ -0,0 +1,13 @@
1
+ import { useContext } from "react";
2
+ import { PageContext } from "../context/PageContext";
3
+ import { SchemaItemType } from "../typing";
4
+
5
+ export const useMethods = (item: SchemaItemType) => {
6
+ const { handleMethod } = useContext(PageContext);
7
+
8
+ const callMethod = (targetId: string, methodName: string, arg?: any) => {
9
+ return handleMethod(item, targetId, methodName, arg);
10
+ };
11
+
12
+ return { callMethod };
13
+ };
@@ -2,7 +2,7 @@ import React from "react";
2
2
  import { createFromIconfontCN } from "@ant-design/icons";
3
3
 
4
4
  const IconFontCN = createFromIconfontCN({
5
- scriptUrl: "https://at.alicdn.com/t/c/font_5072483_x7q8s0iz0m.js",
5
+ scriptUrl: "https://at.alicdn.com/t/c/font_5072483_3ofyyta7h1e.js",
6
6
  });
7
7
 
8
8
  export type IconFontProps = {
@@ -4,7 +4,7 @@ import { PageContext } from "../context/PageContext";
4
4
  import { SchemaItemType } from "../typing";
5
5
  import styled from "styled-components";
6
6
  import { IconFont } from "../icon/IconFont";
7
- import { DeleteOutlined } from "@ant-design/icons";
7
+ import { CopyOutlined, DeleteOutlined } from "@ant-design/icons";
8
8
  import { Button, Dropdown, Modal, Space, Tooltip, Typography } from "antd";
9
9
  import ReactDOM from "react-dom";
10
10
  import { Editor } from "@monaco-editor/react";
@@ -12,6 +12,7 @@ import { Editor } from "@monaco-editor/react";
12
12
  export type PageItemProps = {
13
13
  id?: string;
14
14
  item: SchemaItemType;
15
+ onCopy?: (item: SchemaItemType) => void;
15
16
  onDelete?: () => void;
16
17
  ancestors: SchemaItemType[];
17
18
  parentList?: any[];
@@ -67,9 +68,10 @@ const Toolbar: React.FC<{
67
68
  ancestors: SchemaItemType[];
68
69
  onAddAt?: (e: any) => void;
69
70
  onDelete?: (e: any) => void;
71
+ onCopy?: (e: any) => void;
70
72
  onUpdate?: () => void;
71
73
  onSelect?: (item: SchemaItemType) => void;
72
- }> = ({ item, ancestors, onAddAt, onDelete, onUpdate, onSelect }) => {
74
+ }> = ({ item, ancestors, onAddAt, onDelete, onCopy, onUpdate, onSelect }) => {
73
75
  const [code, setCode] = useState(JSON.stringify(item || {}, null, 2));
74
76
  const [visible, setVisible] = useState(false);
75
77
  const editRef = useRef<any>(null);
@@ -190,6 +192,11 @@ const Toolbar: React.FC<{
190
192
  <IconFont type="icon-json" />
191
193
  </a>
192
194
  </Tooltip>
195
+ <Tooltip title="复制">
196
+ <a onClick={onCopy}>
197
+ <CopyOutlined />
198
+ </a>
199
+ </Tooltip>
193
200
  <Tooltip title="删除">
194
201
  <a onClick={onDelete}>
195
202
  <DeleteOutlined />
@@ -218,6 +225,7 @@ const Toolbar: React.FC<{
218
225
  */
219
226
  export const PageItem: React.FC<PageItemProps> = ({
220
227
  item,
228
+ onCopy,
221
229
  onDelete,
222
230
  ancestors,
223
231
  parentList,
@@ -252,6 +260,11 @@ export const PageItem: React.FC<PageItemProps> = ({
252
260
  });
253
261
  };
254
262
 
263
+ const handleCopy = (e: any) => {
264
+ e.stopPropagation();
265
+ if (onCopy) onCopy(item);
266
+ };
267
+
255
268
  const handleAddAtItem = (e: any) => {
256
269
  e.stopPropagation();
257
270
  if (onAddAtItem) onAddAtItem(item);
@@ -303,6 +316,7 @@ export const PageItem: React.FC<PageItemProps> = ({
303
316
 
304
317
  if (selectedItem && selectedItem === item && designable) {
305
318
  const div = document.createElement("div");
319
+ div.setAttribute("id", "page-item-toolbar")
306
320
  div.style.position = "absolute";
307
321
  div.style.zIndex = "1000";
308
322
  div.style.display = "flex";
@@ -378,6 +392,7 @@ export const PageItem: React.FC<PageItemProps> = ({
378
392
  item={item}
379
393
  ancestors={ancestors}
380
394
  onAddAt={fetch?.ai?.chat ? handleAddAtItem : undefined}
395
+ onCopy={handleCopy}
381
396
  onDelete={handleDelete}
382
397
  onUpdate={forceUpdate}
383
398
  onSelect={onSelect}
@@ -0,0 +1,186 @@
1
+ import { CaretDownOutlined, PlusOutlined } from "@ant-design/icons";
2
+ import { Divider, Dropdown, Empty, Space } from "antd";
3
+ import React, { useContext, useMemo } from "react";
4
+ import styled from "styled-components";
5
+ import { PageContext } from "../context/PageContext";
6
+ import { PluginType } from "../typing";
7
+ import { PaneHeader } from "./PaneHeader";
8
+ import { Editor } from "@monaco-editor/react";
9
+ import { IconFont } from "../icon/IconFont";
10
+
11
+ const Root = styled.div`
12
+ display: flex;
13
+ flex-direction: column;
14
+ height: 100%;
15
+ .body {
16
+ flex: 1 1 auto;
17
+ display: flex;
18
+ flex-direction: column;
19
+ gap: 12px;
20
+ padding: 12px;
21
+ overflow-y: auto;
22
+ overflow-x: hidden;
23
+
24
+ .ant-divider {
25
+ margin: 0;
26
+ }
27
+ }
28
+ ul {
29
+ list-style: none;
30
+ padding: 0;
31
+ margin: 0;
32
+
33
+ li {
34
+ list-style: none;
35
+ padding: 0;
36
+ margin: 0;
37
+ display: flex;
38
+ flex-direction: column;
39
+ border-bottom: 1px dotted #d9d9d9;
40
+ padding-bottom: 8px;
41
+
42
+ & > div:first-child {
43
+ font-size: 14px;
44
+ color: var(--ant-color-text-label);
45
+ padding: 6px 0;
46
+ }
47
+
48
+ &:last-child {
49
+ border-bottom: none;
50
+ }
51
+ }
52
+ }
53
+ ul.tips {
54
+ padding-left: 20px;
55
+ li {
56
+ display: list-item;
57
+ list-style: disc;
58
+ border-bottom: none;
59
+ color: var(--ant-color-text-secondary);
60
+ }
61
+ }
62
+ a.toolbar {
63
+ font-size: 16px;
64
+ color: var(--ant-color-text-secondary);
65
+ }
66
+ `;
67
+
68
+ export const EventPanel: React.FC = ({}) => {
69
+ const { selectedItem, setSelectedItem, plugins, forceUpdate } =
70
+ useContext(PageContext);
71
+ const selectedPlugin: PluginType | undefined = useMemo(() => {
72
+ return (plugins || []).find((p) => p.key === selectedItem?.type);
73
+ }, [plugins, selectedItem?.type]);
74
+
75
+ const events = selectedPlugin?.events || [];
76
+ const eventMap = events.reduce((prev: Record<string, string>, cur) => {
77
+ prev[cur.handler] = cur.name;
78
+ return prev;
79
+ }, {});
80
+
81
+ const onChange = (events: { name: string; script: string }[]) => {
82
+ if (!selectedItem) return;
83
+ setSelectedItem(Object.assign(selectedItem, { events }));
84
+ forceUpdate();
85
+ };
86
+
87
+ return (
88
+ <Root className="cascade-panel">
89
+ <PaneHeader
90
+ title="事件"
91
+ extra={
92
+ selectedPlugin?.events ? (
93
+ <Space>
94
+ <Dropdown
95
+ menu={{
96
+ onClick: ({ key }) => {
97
+ const nextEvents = [...(selectedItem?.events || [])];
98
+ nextEvents.push({ name: key, script: "" });
99
+ onChange && onChange(nextEvents);
100
+ },
101
+ items: events
102
+ .filter(
103
+ (e) =>
104
+ !(selectedItem?.events || [])?.some((i) => i.name === e.handler),
105
+ )
106
+ .map((it) => ({
107
+ key: it.handler,
108
+ label: `${it.name}(${it.handler})`,
109
+ })),
110
+ }}
111
+ placement="bottomRight"
112
+ trigger={["click"]}
113
+ >
114
+ <a className="toolbar">
115
+ <PlusOutlined />
116
+ <CaretDownOutlined
117
+ style={{ fontSize: 8, verticalAlign: "sub" }}
118
+ />
119
+ </a>
120
+ </Dropdown>
121
+ </Space>
122
+ ) : null
123
+ }
124
+ />
125
+ <div className="body beautified_scrollbar">
126
+ <Divider>事件列表</Divider>
127
+ {!!selectedItem?.events?.length ? (
128
+ <ul>
129
+ {(selectedItem.events || []).map(
130
+ ({ name, script }, index: number) => (
131
+ <li key={name}>
132
+ <div>
133
+ <IconFont type="icon-thunderbolt" /> {eventMap[name]}(
134
+ {name})
135
+ </div>
136
+ <div
137
+ style={{
138
+ border: "solid 1px var(--ant-color-border)",
139
+ borderRadius: "var(--ant-border-radius-sm)",
140
+ }}
141
+ >
142
+ <Editor
143
+ height="200px"
144
+ defaultLanguage="javascript"
145
+ value={script || ""}
146
+ onChange={(v) => {
147
+ const nextEvents = [...(selectedItem?.events || [])];
148
+ nextEvents[index].script = v || "";
149
+ onChange && onChange(nextEvents);
150
+ }}
151
+ options={{
152
+ minimap: { enabled: false },
153
+ scrollBeyondLastLine: false,
154
+ tabSize: 2,
155
+ }}
156
+ />
157
+ </div>
158
+ </li>
159
+ ),
160
+ )}
161
+ </ul>
162
+ ) : (
163
+ <Empty description="暂无事件" image={Empty.PRESENTED_IMAGE_SIMPLE} />
164
+ )}
165
+ <Divider>脚本说明</Divider>
166
+ <div>
167
+ <ul className="tips">
168
+ <li>
169
+ 内置参数:param(类型:Object)
170
+ <ul style={{ margin: "8px 0 0 20px" }}>
171
+ <li>param.item: 当前事件触发的组件。</li>
172
+ <li>param.sourceId: 当前事件触发的组件ID。</li>
173
+ <li>param.arg: 事件触发时传递的参数。</li>
174
+ </ul>
175
+ </li>
176
+ <li>
177
+ 脚本禁止使用以下 API:window, document, global, process, require,
178
+ module, exports, cookie, localStorage, sessionStorage。
179
+ </li>
180
+ <li>组件方法调用:callMethod(targetId, methodName, arg)。</li>
181
+ </ul>
182
+ </div>
183
+ </div>
184
+ </Root>
185
+ );
186
+ };