bi-sdk-react 0.0.2 → 0.0.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bi-sdk-react",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "dist/umd/js/bi-sdk.umd.min.js",
@@ -2,6 +2,7 @@ import {
2
2
  DesktopOutlined,
3
3
  EyeInvisibleOutlined,
4
4
  EyeOutlined,
5
+ ImportOutlined,
5
6
  MobileOutlined,
6
7
  RedoOutlined,
7
8
  SaveOutlined,
@@ -10,13 +11,12 @@ import {
10
11
  ZoomInOutlined,
11
12
  ZoomOutOutlined,
12
13
  } from "@ant-design/icons";
13
- import { Button, Divider, Radio, Space, Tooltip } from "antd";
14
+ import { Button, Divider, Modal, Radio, Space, Tooltip } from "antd";
14
15
  import React, {
15
- useEffect,
16
16
  useImperativeHandle,
17
17
  useMemo,
18
18
  useRef,
19
- useState,
19
+ useState
20
20
  } from "react";
21
21
  import styled from "styled-components";
22
22
  import { IconFont } from "./icon/IconFont";
@@ -32,10 +32,11 @@ import { PropertiesPanel } from "./panel/PropertiesPanel";
32
32
  import { ScriptPanel } from "./panel/ScriptPanel";
33
33
  import { VariablesPanel } from "./panel/VariablesPanel";
34
34
 
35
- import { PageSchema, PluginType } from "./typing";
35
+ import { Editor } from "@monaco-editor/react";
36
36
  import { DesignerProvider } from "./context/DesignerContext";
37
37
  import { useDeepCompareEffect } from "./hooks/useDeepCompareEffect";
38
38
  import "./styles.css";
39
+ import { PageSchema, PluginType } from "./typing";
39
40
 
40
41
  export type PageDesignerProps = {
41
42
  agentList?: any[];
@@ -135,6 +136,46 @@ const Container = styled.div`
135
136
  }
136
137
  `;
137
138
 
139
+ const ImportModal: React.FC<{
140
+ open?: boolean;
141
+ onCancel?: () => void;
142
+ onOk?: (schema: PageSchema) => void;
143
+ }> = ({ open, onCancel, onOk }) => {
144
+ const [importSchema, setImportSchema] = useState<string>(
145
+ JSON.stringify({
146
+ info: {},
147
+ datasources: [],
148
+ scripts: [],
149
+ variables: [],
150
+ items: [],
151
+ })
152
+ );
153
+ return (
154
+ <Modal
155
+ title="导入页面"
156
+ open={open}
157
+ width={800}
158
+ onCancel={onCancel}
159
+ onOk={() => onOk?.(JSON.parse(importSchema))}
160
+ okText="导入"
161
+ cancelText="取消"
162
+ styles={{ body: { height: "calc(100vh - 250px)", overflow: "auto" } }}
163
+ >
164
+ <div className="body" style={{ flex: "1 1 auto", display: "flex", height: "100%" }}>
165
+ <Editor
166
+ height="100%"
167
+ defaultLanguage="json"
168
+ value={importSchema}
169
+ options={{
170
+ minimap: { enabled: false },
171
+ }}
172
+ onChange={(v) => setImportSchema(v || "")}
173
+ />
174
+ </div>
175
+ </Modal>
176
+ );
177
+ };
178
+
138
179
  export const PageDesigner = React.forwardRef<any, PageDesignerProps>(
139
180
  ({ agentList = [], plugins = [], headerExtra }, ref) => {
140
181
  const pageCanvasRef = useRef<any>(null);
@@ -162,6 +203,7 @@ export const PageDesigner = React.forwardRef<any, PageDesignerProps>(
162
203
  items: [],
163
204
  });
164
205
  const [designable, setDesignable] = useState(true);
206
+ const [importModalOpen, setImportModalOpen] = useState(false);
165
207
  const containerStyle = useMemo(() => {
166
208
  const left = showLeft ? "250px" : "";
167
209
  const right = showRight ? "400px" : "";
@@ -252,6 +294,15 @@ export const PageDesigner = React.forwardRef<any, PageDesignerProps>(
252
294
  setTimeout(() => pageCanvasRef.current?.handleResize?.(), 0);
253
295
  };
254
296
 
297
+ const handleImportClick = () => {
298
+ setImportModalOpen(true);
299
+ };
300
+
301
+ const handleImportOk = (s: PageSchema) => {
302
+ setImportModalOpen(false);
303
+ setSchema(s);
304
+ };
305
+
255
306
  return (
256
307
  <DesignerProvider
257
308
  designable={designable}
@@ -300,6 +351,15 @@ export const PageDesigner = React.forwardRef<any, PageDesignerProps>(
300
351
  <RedoOutlined />
301
352
  </a>
302
353
  </Tooltip>
354
+ <Divider orientation="vertical" />
355
+ <Tooltip title="导入JSON">
356
+ <a
357
+ className={`toolbar ${future.length > 0 ? "active" : ""}`}
358
+ onClick={handleImportClick}
359
+ >
360
+ <ImportOutlined />
361
+ </a>
362
+ </Tooltip>
303
363
  </Space>
304
364
  <Space>
305
365
  <Tooltip title="缩小">
@@ -501,6 +561,11 @@ export const PageDesigner = React.forwardRef<any, PageDesignerProps>(
501
561
  </div>
502
562
  </Container>
503
563
  </div>
564
+ <ImportModal
565
+ open={importModalOpen}
566
+ onOk={handleImportOk}
567
+ onCancel={() => setImportModalOpen(false)}
568
+ />
504
569
  </DesignerProvider>
505
570
  );
506
571
  }
@@ -1,3 +1,17 @@
1
+ import {
2
+ DeleteOutlined,
3
+ PaperClipOutlined,
4
+ SendOutlined,
5
+ } from "@ant-design/icons";
6
+ import {
7
+ Button,
8
+ Dropdown,
9
+ Input,
10
+ Switch,
11
+ Tooltip,
12
+ Typography,
13
+ Upload,
14
+ } from "antd";
1
15
  import React, {
2
16
  useEffect,
3
17
  useImperativeHandle,
@@ -6,9 +20,8 @@ import React, {
6
20
  useState,
7
21
  } from "react";
8
22
  import styled from "styled-components";
9
- import { Input, Button, Space, Tooltip, Dropdown, Switch, Upload } from "antd";
10
- import { PaperClipOutlined, SendOutlined } from "@ant-design/icons";
11
23
  import * as XLSX from "xlsx";
24
+ import { IconFont } from "../icon/IconFont";
12
25
 
13
26
  export type ChatInputProps = {
14
27
  value?: string;
@@ -24,7 +37,7 @@ export type ChatInputProps = {
24
37
  onSubmit?: (data: {
25
38
  demand: string;
26
39
  title: string;
27
- agentId?: string | number;
40
+ agentIds?: (string | number)[];
28
41
  csvData: Record<string, string>;
29
42
  }) => void;
30
43
  onUpdateTitle?: (title: string) => void;
@@ -93,6 +106,11 @@ const Wrapper = styled.div`
93
106
  background-color: #fafafa;
94
107
  font-size: 12px;
95
108
  position: relative;
109
+
110
+ .anticon {
111
+ font-size: 36px;
112
+ color: var(--ant-green-8);
113
+ }
96
114
  }
97
115
  .attachment-card .name {
98
116
  max-width: 80px;
@@ -108,9 +126,19 @@ const Wrapper = styled.div`
108
126
  position: absolute;
109
127
  top: 4px;
110
128
  right: 2px;
129
+
130
+ .anticon {
131
+ font-size: 12px;
132
+ color: var(--ant-color-text-tertiary);
133
+ }
111
134
  }
112
135
  .attachment-card .remove:hover {
113
136
  color: #666;
137
+
138
+ .anticon {
139
+ font-size: 12px;
140
+ color: var(--ant-color-text-secondary);
141
+ }
114
142
  }
115
143
  .agent-info {
116
144
  box-sizing: border-box;
@@ -120,11 +148,17 @@ const Wrapper = styled.div`
120
148
  border-bottom: none;
121
149
  background-color: #eff1f9;
122
150
  font-size: 14px;
123
- color: #555;
151
+ color: var(--ant-color-text-label);
124
152
  display: flex;
125
153
  align-items: center;
126
- justify-content: space-between;
154
+ flex-wrap: wrap;
127
155
  user-select: none;
156
+ gap: 8px;
157
+
158
+ a {
159
+ color: var(--ant-color-text-disabled);
160
+ margin-left: 4px;
161
+ }
128
162
  }
129
163
  .attachment-bar + .agent-info {
130
164
  border-radius: 0;
@@ -249,7 +283,7 @@ const Wrapper = styled.div`
249
283
  width: 50px;
250
284
  height: 26px;
251
285
  color: #fff;
252
- font-size: 22px;
286
+ font-size: 14px;
253
287
  background-color: rgb(184, 184, 191);
254
288
  border: unset;
255
289
  border-radius: 14px;
@@ -257,7 +291,7 @@ const Wrapper = styled.div`
257
291
  cursor: pointer;
258
292
  }
259
293
  .send-btn.send-btn-active {
260
- background-color: var(--chat-blue);
294
+ background-color: var(--ant-color-primary);
261
295
  }
262
296
  `;
263
297
 
@@ -289,13 +323,12 @@ export const ChatInput = React.forwardRef<
289
323
  ) => {
290
324
  const inputRef = useRef<any>(null);
291
325
  const [localTitle, setLocalTitle] = useState(title || "");
292
- const [localAgentId, setLocalAgentId] = useState<string | number | null>(
293
- agentId || null
294
- );
295
- const [selectedAgent, setSelectedAgent] = useState<{
296
- id: string | number;
297
- name: string;
298
- } | null>(null);
326
+ const [selectedAgent, setSelectedAgent] = useState<
327
+ {
328
+ id: string | number;
329
+ name: string;
330
+ }[]
331
+ >([]);
299
332
  const [localValue, setLocalValue] = useState(value || "");
300
333
  const [lastSubmitAt, setLastSubmitAt] = useState(0);
301
334
  const minIntervalMs = 400;
@@ -316,21 +349,17 @@ export const ChatInput = React.forwardRef<
316
349
  onInput && onInput(localValue);
317
350
  }, [localValue]);
318
351
  useEffect(() => setLocalTitle(title || ""), [title]);
319
- useEffect(() => {
320
- setLocalAgentId(agentId || null);
321
- setSelectedAgent(
322
- agentId ? agentList.find((s) => s.id === agentId) || null : null
323
- );
324
- }, [agentId, agentList]);
352
+ // useEffect(() => {
353
+ // setSelectedAgent(
354
+ // agentId ? agentList.find((s) => s.id === agentId) || [] : []
355
+ // );
356
+ // }, [agentId, agentList]);
325
357
  useEffect(
326
358
  () => setLocalAttachments(Array.isArray(attachments) ? attachments : []),
327
359
  [attachments]
328
360
  );
329
361
  const canSubmit = !!(localValue && localValue.trim());
330
- const agent = useMemo(() => {
331
- if (!localAgentId) return null;
332
- return agentList.find((it) => it.id === localAgentId) || null;
333
- }, [localAgentId, agentList]);
362
+
334
363
  const onTitleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
335
364
  const v = e.target.value;
336
365
  setLocalTitle(v);
@@ -338,14 +367,12 @@ export const ChatInput = React.forwardRef<
338
367
  };
339
368
  const onAgentSelect = (item: { id: string | number; name: string }) => {
340
369
  const id = item.id || null;
341
- setLocalAgentId(id);
342
370
  onUpdateAgentId && onUpdateAgentId(id);
343
- setSelectedAgent(item);
371
+ setSelectedAgent((prev) => [...prev, item]);
344
372
  };
345
- const clearAgent = () => {
346
- setLocalAgentId(null);
373
+ const onRemoveAgent = (index: number) => {
347
374
  onUpdateAgentId && onUpdateAgentId(null);
348
- setSelectedAgent(null);
375
+ setSelectedAgent((prev) => prev.filter((_, i) => i !== index));
349
376
  };
350
377
  const onKeydown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
351
378
  if (e.key === "Enter") {
@@ -415,7 +442,7 @@ export const ChatInput = React.forwardRef<
415
442
  const data = {
416
443
  demand: text,
417
444
  title: showTitle ? localTitle : "",
418
- agentId: localAgentId || undefined,
445
+ agentIds: selectedAgent.map((it) => it.id),
419
446
  csvData: localAttachments.reduce(
420
447
  (acc, a) => ({ ...acc, [a.name]: a.csvBySheet }),
421
448
  {}
@@ -442,31 +469,34 @@ export const ChatInput = React.forwardRef<
442
469
  {localAttachments.length > 0 && (
443
470
  <div className="attachment-bar">
444
471
  {localAttachments.map((a) => (
445
- <Tooltip
446
- key={a.uid}
447
- title={a.name}
448
- className="attachment-card"
449
- >
450
- <svg style={{ width: 25, height: 25 }} viewBox="0 0 24 24">
451
- <rect x="3" y="3" width="18" height="18" fill="#1f6f43" />
452
- </svg>
453
- <span className="name">{a.name}</span>
472
+ <div className="attachment-card">
473
+ <IconFont type="icon-excel" />
474
+ <Typography.Text
475
+ className="name"
476
+ ellipsis={{ tooltip: a.name }}
477
+ >
478
+ {a.name}
479
+ </Typography.Text>
454
480
  <a
455
481
  className="remove"
456
482
  onClick={() => removeAttachment(a.uid)}
457
483
  >
458
- ×
484
+ <DeleteOutlined />
459
485
  </a>
460
- </Tooltip>
486
+ </div>
461
487
  ))}
462
488
  </div>
463
489
  )}
464
- {selectedAgent && (
490
+ {selectedAgent.length > 0 && (
465
491
  <div className="agent-info">
466
- <span className="name">@ {selectedAgent.name}</span>
467
- <a className="remove" onClick={clearAgent}>
468
- ×
469
- </a>
492
+ {selectedAgent.map((item, index) => (
493
+ <div key={String(item.id)}>
494
+ <span className="name">@ {item.name}</span>
495
+ <a className="remove" onClick={() => onRemoveAgent(index)}>
496
+ ×
497
+ </a>
498
+ </div>
499
+ ))}
470
500
  </div>
471
501
  )}
472
502
  {showTitle && (
@@ -197,8 +197,8 @@ export const PropertiesPanel: React.FC = () => {
197
197
  <Form labelCol={{ span: 24 }} wrapperCol={{ span: 24 }}>
198
198
  <Form.Item
199
199
  label="组件标识"
200
- labelCol={{ span: 12 }}
201
- wrapperCol={{ span: 12 }}
200
+ labelCol={{ span: 5 }}
201
+ wrapperCol={{ span: 19 }}
202
202
  >
203
203
  {selectedItem?.id || ""}
204
204
  </Form.Item>
@@ -184,7 +184,6 @@ export const HtmlPlugin: PluginType = {
184
184
  custom: `{"name": "Confucius"}`,
185
185
  },
186
186
  props: {
187
- dataSource: { name: "Confucius" },
188
187
  template: `<div>{{name}}, welcome to the world of programming.</div>`,
189
188
  },
190
189
  },
@@ -84,7 +84,7 @@ export const CapsuleProps: React.FC<PropEditorProps<CapsuleModel>> = ({
84
84
  <Radio.Button value="large">大</Radio.Button>
85
85
  </Radio.Group>
86
86
  </Form.Item>
87
- <Form.Item>
87
+ <Form.Item labelCol={{ span: 24 }} wrapperCol={{ span: 24 }}>
88
88
  <Table
89
89
  size="small"
90
90
  dataSource={model.options}
@@ -1,75 +1,123 @@
1
- import React from 'react'
2
- import { Form, Input, Radio, InputNumber, Table, Button, Space, Switch } from 'antd'
3
- import type { PropEditorProps } from './types'
4
- import { DeleteOutlined } from '@ant-design/icons';
1
+ import React from "react";
2
+ import {
3
+ Form,
4
+ Input,
5
+ Radio,
6
+ InputNumber,
7
+ Table,
8
+ Button,
9
+ Space,
10
+ Switch,
11
+ } from "antd";
12
+ import type { PropEditorProps } from "./types";
13
+ import { DeleteOutlined } from "@ant-design/icons";
5
14
 
6
- export type CheckboxOption = { label: string; value: any }
15
+ export type CheckboxOption = { label: string; value: any };
7
16
  export type CheckboxModel = {
8
- var?: string
9
- layout?: 'horizontal' | 'vertical' | 'grid'
10
- lineNumber?: number
11
- options: CheckboxOption[]
12
- }
17
+ var?: string;
18
+ layout?: "horizontal" | "vertical" | "grid";
19
+ lineNumber?: number;
20
+ options: CheckboxOption[];
21
+ };
13
22
 
14
- export const CheckboxProps: React.FC<PropEditorProps<CheckboxModel>> = ({ model, onChange }) => {
15
- const trigger = (key: keyof CheckboxModel, value: any) => onChange && onChange({ ...model, [key]: value })
23
+ export const CheckboxProps: React.FC<PropEditorProps<CheckboxModel>> = ({
24
+ model,
25
+ onChange,
26
+ }) => {
27
+ const trigger = (key: keyof CheckboxModel, value: any) =>
28
+ onChange && onChange({ ...model, [key]: value });
16
29
  const setOption = (index: number, key: keyof CheckboxOption, value: any) => {
17
- const options = [...(model.options || [])]
18
- options[index] = { ...options[index], [key]: value }
19
- trigger('options', options)
20
- }
30
+ const options = [...(model.options || [])];
31
+ options[index] = { ...options[index], [key]: value };
32
+ trigger("options", options);
33
+ };
21
34
  const removeOption = (index: number) => {
22
- const options = [...(model.options || [])]
23
- options.splice(index, 1)
24
- trigger('options', options)
25
- }
35
+ const options = [...(model.options || [])];
36
+ options.splice(index, 1);
37
+ trigger("options", options);
38
+ };
26
39
  const addOption = () => {
27
- trigger('options', [...(model.options || []), { label: '', value: '' }])
28
- }
40
+ trigger("options", [...(model.options || []), { label: "", value: "" }]);
41
+ };
29
42
  const columns = [
30
43
  {
31
- title: '选项标签',
32
- dataIndex: 'label',
33
- render: (_: any, r: CheckboxOption, i: number) => <Input size="small" value={r.label} onChange={e => setOption(i, 'label', e.target.value)} />
44
+ title: "选项标签",
45
+ dataIndex: "label",
46
+ render: (_: any, r: CheckboxOption, i: number) => (
47
+ <Input
48
+ size="small"
49
+ value={r.label}
50
+ onChange={(e) => setOption(i, "label", e.target.value)}
51
+ />
52
+ ),
34
53
  },
35
54
  {
36
- title: '选项值',
37
- dataIndex: 'value',
38
- render: (_: any, r: CheckboxOption, i: number) => <Input size="small" value={r.value} onChange={e => setOption(i, 'value', e.target.value)} />
55
+ title: "选项值",
56
+ dataIndex: "value",
57
+ render: (_: any, r: CheckboxOption, i: number) => (
58
+ <Input
59
+ size="small"
60
+ value={r.value}
61
+ onChange={(e) => setOption(i, "value", e.target.value)}
62
+ />
63
+ ),
39
64
  },
40
65
  {
41
- title: '操作',
66
+ title: "操作",
42
67
  render: (_: any, r: CheckboxOption, i: number) => (
43
68
  <Space>
44
69
  <Button danger size="small" onClick={() => removeOption(i)}>
45
70
  <DeleteOutlined />
46
71
  </Button>
47
72
  </Space>
48
- )
49
- }
50
- ]
73
+ ),
74
+ },
75
+ ];
51
76
  return (
52
77
  <Form labelCol={{ span: 6 }} wrapperCol={{ span: 18 }}>
53
78
  <Form.Item label="变量名">
54
- <Input size="small" value={model.var} onChange={e => trigger('var', e.target.value)} placeholder="请输入变量名" />
79
+ <Input
80
+ size="small"
81
+ value={model.var}
82
+ onChange={(e) => trigger("var", e.target.value)}
83
+ placeholder="请输入变量名"
84
+ />
55
85
  </Form.Item>
56
86
  <Form.Item label="布局">
57
- <Radio.Group size="small" value={model.layout} onChange={e => trigger('layout', e.target.value)}>
87
+ <Radio.Group
88
+ size="small"
89
+ value={model.layout}
90
+ onChange={(e) => trigger("layout", e.target.value)}
91
+ >
58
92
  <Radio.Button value="horizontal">水平</Radio.Button>
59
93
  <Radio.Button value="vertical">垂直</Radio.Button>
60
94
  <Radio.Button value="grid">网格</Radio.Button>
61
95
  </Radio.Group>
62
96
  </Form.Item>
63
- {model.layout === 'grid' && (
97
+ {model.layout === "grid" && (
64
98
  <Form.Item label="网格行数">
65
- <InputNumber size="small" value={model.lineNumber} onChange={v => trigger('lineNumber', v)} min={1} max={10} />
99
+ <InputNumber
100
+ size="small"
101
+ value={model.lineNumber}
102
+ onChange={(v) => trigger("lineNumber", v)}
103
+ min={1}
104
+ max={10}
105
+ />
66
106
  </Form.Item>
67
107
  )}
68
- <Form.Item>
69
- <Table size="small" dataSource={model.options} columns={columns as any} pagination={false} rowKey={(_, i) => String(i)} bordered />
70
- <Button size="small" block onClick={addOption}>添加选项</Button>
108
+ <Form.Item labelCol={{ span: 24 }} wrapperCol={{ span: 24 }}>
109
+ <Table
110
+ size="small"
111
+ dataSource={model.options}
112
+ columns={columns as any}
113
+ pagination={false}
114
+ rowKey={(_, i) => String(i)}
115
+ bordered
116
+ />
117
+ <Button size="small" block onClick={addOption}>
118
+ 添加选项
119
+ </Button>
71
120
  </Form.Item>
72
121
  </Form>
73
- )
74
- }
75
-
122
+ );
123
+ };