bi-sdk-react 0.0.59 → 0.0.60
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/dist/es/js/bi-sdk.es.js +55 -42
- package/dist/types/components/plugins/@antd/index.d.ts +1 -0
- package/dist/types/components/plugins/@antd/item-props/AnchorProps.d.ts +4 -0
- package/dist/types/components/plugins/@antd/item-props/index.d.ts +1 -0
- package/dist/types/components/plugins/@antd/items/AnchorRender.d.ts +32 -0
- package/dist/types/components/plugins/@antd/items/index.d.ts +1 -0
- package/dist/umd/js/bi-sdk.umd.min.js +21 -8
- package/package.json +1 -1
- package/src/components/icon/IconFont.tsx +1 -1
- package/src/components/plugins/@antd/index.ts +32 -3
- package/src/components/plugins/@antd/item-props/AnchorProps.tsx +223 -0
- package/src/components/plugins/@antd/item-props/index.ts +1 -1
- package/src/components/plugins/@antd/items/AnchorRender.tsx +114 -0
- package/src/components/plugins/@antd/items/index.ts +1 -0
package/package.json
CHANGED
|
@@ -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/
|
|
5
|
+
scriptUrl: "https://at.alicdn.com/t/c/font_5072483_qyp3hlby2nr.js",
|
|
6
6
|
});
|
|
7
7
|
|
|
8
8
|
export type IconFontProps = {
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
SwitchProps,
|
|
25
25
|
TableProps,
|
|
26
26
|
TextProps,
|
|
27
|
+
AnchorProps,
|
|
27
28
|
} from "./item-props";
|
|
28
29
|
import {
|
|
29
30
|
ButtonRender,
|
|
@@ -47,6 +48,7 @@ import {
|
|
|
47
48
|
SwitchRender,
|
|
48
49
|
TableRender,
|
|
49
50
|
TextRender,
|
|
51
|
+
AnchorRender,
|
|
50
52
|
} from "./items";
|
|
51
53
|
|
|
52
54
|
export const TextPlugin: PluginType = {
|
|
@@ -140,7 +142,8 @@ export const TablePlugin: PluginType = {
|
|
|
140
142
|
source: "custom",
|
|
141
143
|
datasourceId: null,
|
|
142
144
|
scriptId: null,
|
|
143
|
-
custom:
|
|
145
|
+
custom:
|
|
146
|
+
'[{"name":"苹果","count":12},{"name":"华为","count":803},{"name":"OPPO","count":654},{"name":"vivo","count":719}]',
|
|
144
147
|
},
|
|
145
148
|
props: {
|
|
146
149
|
size: "default",
|
|
@@ -232,6 +235,31 @@ return {
|
|
|
232
235
|
],
|
|
233
236
|
};
|
|
234
237
|
|
|
238
|
+
export const AnchorPlugin: PluginType = {
|
|
239
|
+
group: "基础组件",
|
|
240
|
+
key: "b-anchor",
|
|
241
|
+
label: "锚点",
|
|
242
|
+
icon: "icon-anchor",
|
|
243
|
+
component: AnchorRender,
|
|
244
|
+
formComponent: AnchorProps,
|
|
245
|
+
defaultOptions: {
|
|
246
|
+
props: {
|
|
247
|
+
items: [
|
|
248
|
+
{ href: "#item1", title: "<i class='icon-dict'></i>项目1" },
|
|
249
|
+
{ href: "#item2", title: "<i class='icon-dict'></i>项目2" },
|
|
250
|
+
{ href: "#item3", title: "<i class='icon-dict'></i>项目3" },
|
|
251
|
+
],
|
|
252
|
+
linePosition: 10,
|
|
253
|
+
lineColor: "rgba(5, 5, 5, 0.06)",
|
|
254
|
+
lineWidth: 2,
|
|
255
|
+
gap: 30,
|
|
256
|
+
itemClassNames: [],
|
|
257
|
+
itemTitleClassNames: [],
|
|
258
|
+
indicatorClassNames: [],
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
};
|
|
262
|
+
|
|
235
263
|
export const InputPlugin: PluginType = {
|
|
236
264
|
group: "表单组件",
|
|
237
265
|
key: "b-input",
|
|
@@ -462,7 +490,7 @@ export const ModalPlugin: PluginType = {
|
|
|
462
490
|
events: [
|
|
463
491
|
{ name: "打开", handler: "open" },
|
|
464
492
|
{ name: "关闭", handler: "close" },
|
|
465
|
-
]
|
|
493
|
+
],
|
|
466
494
|
};
|
|
467
495
|
|
|
468
496
|
export const DrawerPlugin: PluginType = {
|
|
@@ -492,7 +520,7 @@ export const DrawerPlugin: PluginType = {
|
|
|
492
520
|
events: [
|
|
493
521
|
{ name: "打开", handler: "open" },
|
|
494
522
|
{ name: "关闭", handler: "close" },
|
|
495
|
-
]
|
|
523
|
+
],
|
|
496
524
|
};
|
|
497
525
|
|
|
498
526
|
export const plugins: PluginType[] = [
|
|
@@ -504,6 +532,7 @@ export const plugins: PluginType[] = [
|
|
|
504
532
|
ListPlugin,
|
|
505
533
|
HtmlPlugin,
|
|
506
534
|
EchartsPlugin,
|
|
535
|
+
AnchorPlugin,
|
|
507
536
|
InputPlugin,
|
|
508
537
|
InputNumberPlugin,
|
|
509
538
|
SelectPlugin,
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { DeleteOutlined, EditOutlined } from "@ant-design/icons";
|
|
2
|
+
import {
|
|
3
|
+
AutoComplete,
|
|
4
|
+
Button,
|
|
5
|
+
ColorPicker,
|
|
6
|
+
Divider,
|
|
7
|
+
Form,
|
|
8
|
+
Input,
|
|
9
|
+
InputNumber,
|
|
10
|
+
Modal,
|
|
11
|
+
Select,
|
|
12
|
+
Space,
|
|
13
|
+
Table,
|
|
14
|
+
} from "antd";
|
|
15
|
+
import React, { useContext, useMemo, useState } from "react";
|
|
16
|
+
import { AnchorItem, AnchorRenderProps } from "../items/AnchorRender";
|
|
17
|
+
import type { PropEditorProps } from "./types";
|
|
18
|
+
import { PageContext } from "../../../context/PageContext";
|
|
19
|
+
|
|
20
|
+
export const AnchorProps: React.FC<PropEditorProps<AnchorRenderProps>> = ({
|
|
21
|
+
model,
|
|
22
|
+
onChange,
|
|
23
|
+
}) => {
|
|
24
|
+
const { schema } = useContext(PageContext);
|
|
25
|
+
|
|
26
|
+
const trigger = (key: keyof AnchorRenderProps, value: any) =>
|
|
27
|
+
onChange && onChange({ ...model, [key]: value });
|
|
28
|
+
const setColumn = (index: number, col: Partial<AnchorItem>) => {
|
|
29
|
+
const items = [...(model.items || [])];
|
|
30
|
+
items[index] = { ...items[index], ...col };
|
|
31
|
+
trigger("items", items);
|
|
32
|
+
};
|
|
33
|
+
const removeColumn = (index: number) => {
|
|
34
|
+
const items = [...(model.items || [])];
|
|
35
|
+
items.splice(index, 1);
|
|
36
|
+
trigger("items", items);
|
|
37
|
+
};
|
|
38
|
+
const addColumn = () => {
|
|
39
|
+
trigger("items", [
|
|
40
|
+
...(model.items || []),
|
|
41
|
+
{ title: "", href: "", key: "" },
|
|
42
|
+
]);
|
|
43
|
+
};
|
|
44
|
+
const [editVisible, setEditVisible] = useState(false);
|
|
45
|
+
const [editingIndex, setEditingIndex] = useState<number | null>(null);
|
|
46
|
+
const editingForm =
|
|
47
|
+
editingIndex != null && model.items?.[editingIndex]
|
|
48
|
+
? model.items[editingIndex]
|
|
49
|
+
: { title: "", href: "", key: "" };
|
|
50
|
+
const columns = [
|
|
51
|
+
{
|
|
52
|
+
title: "标题",
|
|
53
|
+
dataIndex: "title",
|
|
54
|
+
render: (v: string) => (
|
|
55
|
+
<div dangerouslySetInnerHTML={{ __html: v }}></div>
|
|
56
|
+
),
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
title: "操作",
|
|
60
|
+
width: 80,
|
|
61
|
+
align: "center" as const,
|
|
62
|
+
render: (_: any, r: AnchorItem, i: number) => (
|
|
63
|
+
<Space>
|
|
64
|
+
<a
|
|
65
|
+
onClick={() => {
|
|
66
|
+
setEditingIndex(i);
|
|
67
|
+
setEditVisible(true);
|
|
68
|
+
}}
|
|
69
|
+
>
|
|
70
|
+
<EditOutlined />
|
|
71
|
+
</a>
|
|
72
|
+
<a onClick={() => removeColumn(i)}>
|
|
73
|
+
<DeleteOutlined />
|
|
74
|
+
</a>
|
|
75
|
+
</Space>
|
|
76
|
+
),
|
|
77
|
+
},
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
const items = useMemo(() => {
|
|
81
|
+
const list: any[] = [];
|
|
82
|
+
const compute = (arr?: any[]) => {
|
|
83
|
+
if (!Array.isArray(arr)) return;
|
|
84
|
+
arr.forEach((item) => {
|
|
85
|
+
list.push(item);
|
|
86
|
+
if (Array.isArray(item.children)) {
|
|
87
|
+
compute(item.children);
|
|
88
|
+
} else if (typeof item.children === "object" && item.children) {
|
|
89
|
+
Object.keys(item.children).forEach((k) => compute(item.children[k]));
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
compute(schema?.items || []);
|
|
94
|
+
return list;
|
|
95
|
+
}, [schema]);
|
|
96
|
+
|
|
97
|
+
return (
|
|
98
|
+
<div>
|
|
99
|
+
<Form labelCol={{ span: 6 }} wrapperCol={{ span: 18 }}>
|
|
100
|
+
<Form.Item label="线位置(left)">
|
|
101
|
+
<InputNumber
|
|
102
|
+
size="small"
|
|
103
|
+
style={{ width: "100px" }}
|
|
104
|
+
value={model.linePosition}
|
|
105
|
+
suffix="px"
|
|
106
|
+
onChange={(v) => trigger("linePosition", v)}
|
|
107
|
+
/>
|
|
108
|
+
</Form.Item>
|
|
109
|
+
<Form.Item label="线颜色">
|
|
110
|
+
<ColorPicker
|
|
111
|
+
size="small"
|
|
112
|
+
value={model.lineColor}
|
|
113
|
+
onChange={(v) => trigger("lineColor", v.toHexString())}
|
|
114
|
+
allowClear={true}
|
|
115
|
+
/>
|
|
116
|
+
</Form.Item>
|
|
117
|
+
<Form.Item label="线宽度">
|
|
118
|
+
<InputNumber
|
|
119
|
+
size="small"
|
|
120
|
+
style={{ width: "100px" }}
|
|
121
|
+
value={model.lineWidth}
|
|
122
|
+
suffix="px"
|
|
123
|
+
onChange={(v) => trigger("lineWidth", v)}
|
|
124
|
+
/>
|
|
125
|
+
</Form.Item>
|
|
126
|
+
<Form.Item label="间距">
|
|
127
|
+
<InputNumber
|
|
128
|
+
size="small"
|
|
129
|
+
style={{ width: "100px" }}
|
|
130
|
+
value={model.gap}
|
|
131
|
+
suffix="px"
|
|
132
|
+
onChange={(v) => trigger("gap", v)}
|
|
133
|
+
/>
|
|
134
|
+
</Form.Item>
|
|
135
|
+
|
|
136
|
+
<Divider style={{ marginTop: 10 }}>样式设置</Divider>
|
|
137
|
+
<Form.Item
|
|
138
|
+
label="链接项类名"
|
|
139
|
+
layout="vertical"
|
|
140
|
+
labelCol={{ span: 24 }}
|
|
141
|
+
wrapperCol={{ span: 24 }}
|
|
142
|
+
>
|
|
143
|
+
<Select
|
|
144
|
+
mode="tags"
|
|
145
|
+
size="small"
|
|
146
|
+
value={model.itemClassNames || []}
|
|
147
|
+
onChange={(e) => trigger("itemClassNames", e)}
|
|
148
|
+
/>
|
|
149
|
+
</Form.Item>
|
|
150
|
+
<Form.Item
|
|
151
|
+
label="标题文字类名"
|
|
152
|
+
layout="vertical"
|
|
153
|
+
labelCol={{ span: 24 }}
|
|
154
|
+
wrapperCol={{ span: 24 }}
|
|
155
|
+
>
|
|
156
|
+
<Select
|
|
157
|
+
mode="tags"
|
|
158
|
+
size="small"
|
|
159
|
+
value={model.itemTitleClassNames || []}
|
|
160
|
+
onChange={(e) => trigger("itemTitleClassNames", e)}
|
|
161
|
+
/>
|
|
162
|
+
</Form.Item>
|
|
163
|
+
<Form.Item
|
|
164
|
+
label="指示器类名"
|
|
165
|
+
layout="vertical"
|
|
166
|
+
labelCol={{ span: 24 }}
|
|
167
|
+
wrapperCol={{ span: 24 }}
|
|
168
|
+
>
|
|
169
|
+
<Select
|
|
170
|
+
mode="tags"
|
|
171
|
+
size="small"
|
|
172
|
+
value={model.indicatorClassNames || []}
|
|
173
|
+
onChange={(e) => trigger("indicatorClassNames", e)}
|
|
174
|
+
/>
|
|
175
|
+
</Form.Item>
|
|
176
|
+
</Form>
|
|
177
|
+
<Divider>锚点项设置</Divider>
|
|
178
|
+
<Table
|
|
179
|
+
size="small"
|
|
180
|
+
dataSource={model.items}
|
|
181
|
+
rowKey={(_, i) => String(i)}
|
|
182
|
+
columns={columns as any}
|
|
183
|
+
pagination={false}
|
|
184
|
+
bordered
|
|
185
|
+
/>
|
|
186
|
+
<Button size="small" onClick={addColumn} block>
|
|
187
|
+
添加列
|
|
188
|
+
</Button>
|
|
189
|
+
<Modal
|
|
190
|
+
title="编辑列"
|
|
191
|
+
open={editVisible}
|
|
192
|
+
footer={null}
|
|
193
|
+
width={400}
|
|
194
|
+
onCancel={() => setEditVisible(false)}
|
|
195
|
+
>
|
|
196
|
+
<Form layout="vertical" size="small">
|
|
197
|
+
<Form.Item
|
|
198
|
+
label="锚点内容"
|
|
199
|
+
tooltip="支持HTML标签"
|
|
200
|
+
style={{ marginBottom: 10 }}
|
|
201
|
+
>
|
|
202
|
+
<Input.TextArea
|
|
203
|
+
value={editingForm.title}
|
|
204
|
+
onChange={(e) =>
|
|
205
|
+
setColumn(editingIndex!, { title: e.target.value })
|
|
206
|
+
}
|
|
207
|
+
/>
|
|
208
|
+
</Form.Item>
|
|
209
|
+
<Form.Item label="锚点链接" style={{ marginBottom: 10 }}>
|
|
210
|
+
<AutoComplete
|
|
211
|
+
value={editingForm.href}
|
|
212
|
+
onChange={(e) => setColumn(editingIndex!, { href: e })}
|
|
213
|
+
options={items.map((i) => ({
|
|
214
|
+
value: i.id,
|
|
215
|
+
label: i.name,
|
|
216
|
+
}))}
|
|
217
|
+
/>
|
|
218
|
+
</Form.Item>
|
|
219
|
+
</Form>
|
|
220
|
+
</Modal>
|
|
221
|
+
</div>
|
|
222
|
+
);
|
|
223
|
+
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { Anchor, Space } from "antd";
|
|
2
|
+
import React, { useContext, useMemo } from "react";
|
|
3
|
+
import { IconFont } from "../../../icon/IconFont";
|
|
4
|
+
import styled from "styled-components";
|
|
5
|
+
import { PageContext } from "../../../context/PageContext";
|
|
6
|
+
import { HtmlBaseProps } from "../../../typing";
|
|
7
|
+
|
|
8
|
+
export type AnchorItem = {
|
|
9
|
+
key?: string;
|
|
10
|
+
href: string;
|
|
11
|
+
title: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type AnchorRenderProps = {
|
|
15
|
+
id?: string;
|
|
16
|
+
item: any;
|
|
17
|
+
items?: AnchorItem[];
|
|
18
|
+
style?: React.CSSProperties;
|
|
19
|
+
linePosition?: number;
|
|
20
|
+
lineColor?: string;
|
|
21
|
+
lineWidth?: number;
|
|
22
|
+
gap?: number;
|
|
23
|
+
itemClassNames?: string[];
|
|
24
|
+
itemTitleClassNames?: string[];
|
|
25
|
+
indicatorClassNames?: string[];
|
|
26
|
+
} & HtmlBaseProps;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* AnchorRender 组件
|
|
30
|
+
* 用途:渲染自定义 HTML 模板,支持数据源变量插值
|
|
31
|
+
* 参数:
|
|
32
|
+
* - id:组件唯一标识
|
|
33
|
+
* - template:HTML 模板字符串,支持 {{ expr }} 插值
|
|
34
|
+
* - item:当前元素数据(含 datasource)
|
|
35
|
+
* - style:样式
|
|
36
|
+
* - className:类名
|
|
37
|
+
* - ref:转发到 div 的引用(HTMLDivElement)
|
|
38
|
+
*/
|
|
39
|
+
export const AnchorRender: React.FC<AnchorRenderProps> = ({
|
|
40
|
+
id,
|
|
41
|
+
item,
|
|
42
|
+
items = [],
|
|
43
|
+
style,
|
|
44
|
+
linePosition = 0,
|
|
45
|
+
lineColor = "rgba(5, 5, 5, 0.06)",
|
|
46
|
+
lineWidth = 2,
|
|
47
|
+
gap = 30,
|
|
48
|
+
itemClassNames = [],
|
|
49
|
+
itemTitleClassNames = [],
|
|
50
|
+
indicatorClassNames = [],
|
|
51
|
+
className,
|
|
52
|
+
}) => {
|
|
53
|
+
const { designable } = useContext(PageContext);
|
|
54
|
+
const anchorItems = useMemo(
|
|
55
|
+
() =>
|
|
56
|
+
items.map((item, index) => ({
|
|
57
|
+
...item,
|
|
58
|
+
key: item.key || index,
|
|
59
|
+
title: <div dangerouslySetInnerHTML={{ __html: item.title }}></div>,
|
|
60
|
+
href: `#page-item-${item.href}`,
|
|
61
|
+
})),
|
|
62
|
+
[items],
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const StyledAnchor = styled(Anchor)`
|
|
66
|
+
.ant-anchor:before {
|
|
67
|
+
inset-inline-start: ${linePosition || 0}px !important;
|
|
68
|
+
border-inline-start-color: ${lineColor ||
|
|
69
|
+
"rgba(5, 5, 5, 0.06)"} !important;
|
|
70
|
+
border-inline-start-width: ${lineWidth || 2}px !important;
|
|
71
|
+
}
|
|
72
|
+
.ant-anchor .ant-anchor-ink.ant-anchor-ink-visible {
|
|
73
|
+
left: ${linePosition || 0}px !important;
|
|
74
|
+
width: ${lineWidth || 2}px !important;
|
|
75
|
+
}
|
|
76
|
+
div.ant-anchor-link + div.ant-anchor-link {
|
|
77
|
+
margin-top: ${gap || 30}px;
|
|
78
|
+
}
|
|
79
|
+
`;
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<div id={id} className={className}>
|
|
83
|
+
<StyledAnchor
|
|
84
|
+
style={style}
|
|
85
|
+
items={anchorItems}
|
|
86
|
+
getContainer={() =>
|
|
87
|
+
designable
|
|
88
|
+
? (document.querySelector(
|
|
89
|
+
".center > .body.beautified_scrollbar.always",
|
|
90
|
+
) as HTMLElement)
|
|
91
|
+
: window
|
|
92
|
+
}
|
|
93
|
+
classNames={{
|
|
94
|
+
item: (itemClassNames || []).join(" "),
|
|
95
|
+
itemTitle: (itemTitleClassNames || []).join(" "),
|
|
96
|
+
indicator: (indicatorClassNames || []).join(" "),
|
|
97
|
+
}}
|
|
98
|
+
styles={{
|
|
99
|
+
item: {
|
|
100
|
+
paddingTop: 0,
|
|
101
|
+
paddingBottom: 0,
|
|
102
|
+
},
|
|
103
|
+
itemTitle: {
|
|
104
|
+
// backgroundColor: "#ffffff",
|
|
105
|
+
},
|
|
106
|
+
indicator: {
|
|
107
|
+
left: `${linePosition || 0}px !important`,
|
|
108
|
+
width: `${lineWidth || 2}px !important`,
|
|
109
|
+
},
|
|
110
|
+
}}
|
|
111
|
+
/>
|
|
112
|
+
</div>
|
|
113
|
+
);
|
|
114
|
+
};
|