@xbeeant/form-engine-designer 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/dist/es/Canvas.js +42 -46
- package/dist/es/Canvas.js.map +1 -1
- package/dist/es/Designer.js +121 -98
- package/dist/es/Designer.js.map +1 -1
- package/dist/es/DesignerContext.js +86 -73
- package/dist/es/DesignerContext.js.map +1 -1
- package/dist/es/Palette.js +3 -3
- package/dist/es/Palette.js.map +1 -1
- package/dist/es/PropertyPanel.js +97 -97
- package/dist/es/PropertyPanel.js.map +1 -1
- package/dist/es/catalog.js +19 -11
- package/dist/es/catalog.js.map +1 -1
- package/dist/es/designer-context.js +110 -0
- package/dist/es/designer-context.js.map +1 -0
- package/dist/es/history.js +73 -0
- package/dist/es/history.js.map +1 -0
- package/dist/es/index.js +3 -3
- package/dist/es/property/basic-property.js +6 -0
- package/dist/es/property/basic-property.js.map +1 -1
- package/dist/es/property-panel.js +294 -0
- package/dist/es/property-panel.js.map +1 -0
- package/dist/es/resizable-panel.js +103 -0
- package/dist/es/resizable-panel.js.map +1 -0
- package/dist/es/schema-utils.js +286 -0
- package/dist/es/schema-utils.js.map +1 -0
- package/dist/es/widgets/BindEditor.js +60 -49
- package/dist/es/widgets/BindEditor.js.map +1 -1
- package/dist/es/widgets/CodeEditor.js +41 -49
- package/dist/es/widgets/CodeEditor.js.map +1 -1
- package/dist/es/widgets/DefaultEditor.js +25 -30
- package/dist/es/widgets/DefaultEditor.js.map +1 -1
- package/dist/es/widgets/DependenciesEditor.js +21 -21
- package/dist/es/widgets/DependenciesEditor.js.map +1 -1
- package/dist/es/widgets/EnumEditor.js +25 -31
- package/dist/es/widgets/EnumEditor.js.map +1 -1
- package/dist/es/widgets/ExpressionSwitch.js +32 -30
- package/dist/es/widgets/ExpressionSwitch.js.map +1 -1
- package/dist/es/widgets/ReactionsEditor.js +103 -103
- package/dist/es/widgets/ReactionsEditor.js.map +1 -1
- package/dist/es/widgets/RemoteDataEditor.js +63 -63
- package/dist/es/widgets/RemoteDataEditor.js.map +1 -1
- package/dist/es/widgets/ValidateEditor.js +49 -49
- package/dist/es/widgets/ValidateEditor.js.map +1 -1
- package/dist/es/widgets/bind-editor.js +78 -0
- package/dist/es/widgets/bind-editor.js.map +1 -0
- package/dist/es/widgets/code-editor.js +76 -0
- package/dist/es/widgets/code-editor.js.map +1 -0
- package/dist/es/widgets/default-editor.js +50 -0
- package/dist/es/widgets/default-editor.js.map +1 -0
- package/dist/es/widgets/dependencies-editor.js +36 -0
- package/dist/es/widgets/dependencies-editor.js.map +1 -0
- package/dist/es/widgets/enum-editor.js +43 -0
- package/dist/es/widgets/enum-editor.js.map +1 -0
- package/dist/es/widgets/expression-builder.js +367 -0
- package/dist/es/widgets/expression-builder.js.map +1 -0
- package/dist/es/widgets/expression-model.js +340 -0
- package/dist/es/widgets/expression-model.js.map +1 -0
- package/dist/es/widgets/expression-switch.js +49 -0
- package/dist/es/widgets/expression-switch.js.map +1 -0
- package/dist/es/widgets/index.js +13 -13
- package/dist/es/widgets/index.js.map +1 -1
- package/dist/es/widgets/options-editor.js +102 -0
- package/dist/es/widgets/options-editor.js.map +1 -0
- package/dist/es/widgets/reactions-editor.js +401 -0
- package/dist/es/widgets/reactions-editor.js.map +1 -0
- package/dist/es/widgets/reactions-model.js +107 -0
- package/dist/es/widgets/reactions-model.js.map +1 -0
- package/dist/es/widgets/remote-data-editor.js +314 -0
- package/dist/es/widgets/remote-data-editor.js.map +1 -0
- package/dist/es/widgets/use-form-data-fields.js +16 -0
- package/dist/es/widgets/use-form-data-fields.js.map +1 -0
- package/dist/es/widgets/validate-editor.js +118 -0
- package/dist/es/widgets/validate-editor.js.map +1 -0
- package/package.json +4 -5
- package/dist/es/react/src/components/FormController.js +0 -154
- package/dist/es/react/src/components/FormController.js.map +0 -1
- package/dist/es/react/src/components/NexusField.js +0 -99
- package/dist/es/react/src/components/NexusField.js.map +0 -1
- package/dist/es/react/src/components/NexusForm.js +0 -121
- package/dist/es/react/src/components/NexusForm.js.map +0 -1
- package/dist/es/react/src/components/NexusFormProvider.js +0 -19
- package/dist/es/react/src/components/NexusFormProvider.js.map +0 -1
- package/dist/es/react/src/components/NexusLayout.js +0 -49
- package/dist/es/react/src/components/NexusLayout.js.map +0 -1
- package/dist/es/react/src/components/NexusObject.js +0 -65
- package/dist/es/react/src/components/NexusObject.js.map +0 -1
- package/dist/es/react/src/contexts/FieldInheritContext.js +0 -6
- package/dist/es/react/src/contexts/FieldInheritContext.js.map +0 -1
- package/dist/es/react/src/contexts/GridContext.js +0 -6
- package/dist/es/react/src/contexts/GridContext.js.map +0 -1
- package/dist/es/react/src/contexts/LayoutConfigContext.js +0 -6
- package/dist/es/react/src/contexts/LayoutConfigContext.js.map +0 -1
- package/dist/es/react/src/contexts/NexusContext.js +0 -13
- package/dist/es/react/src/contexts/NexusContext.js.map +0 -1
- package/dist/es/react/src/hooks/useForm.js +0 -10
- package/dist/es/react/src/hooks/useForm.js.map +0 -1
- package/dist/es/react/src/utils/renderTreeNode.js +0 -18
- package/dist/es/react/src/utils/renderTreeNode.js.map +0 -1
- package/dist/es/react/src/utils/resolveColSpan.js +0 -10
- package/dist/es/react/src/utils/resolveColSpan.js.map +0 -1
- package/dist/es/schemaUtils.test.js +0 -188
- package/dist/es/schemaUtils.test.js.map +0 -1
- package/dist/es/vite-env.d.js +0 -2
- package/dist/es/vite-env.d.js.map +0 -1
- package/dist/es/widgets/expressionModel.test.js +0 -193
- package/dist/es/widgets/expressionModel.test.js.map +0 -1
- package/src/Canvas.tsx +0 -1111
- package/src/Designer.css +0 -206
- package/src/Designer.tsx +0 -254
- package/src/DesignerContext.tsx +0 -192
- package/src/Palette.tsx +0 -261
- package/src/PropertyPanel.tsx +0 -486
- package/src/ResizablePanel.tsx +0 -210
- package/src/catalog.ts +0 -526
- package/src/index.ts +0 -25
- package/src/property/basic-property.ts +0 -126
- package/src/schemaUtils.test.ts +0 -261
- package/src/schemaUtils.ts +0 -627
- package/src/types.ts +0 -38
- package/src/vite-env.d.ts +0 -1
- package/src/widgets/BindEditor.tsx +0 -105
- package/src/widgets/CodeEditor.tsx +0 -114
- package/src/widgets/DefaultEditor.tsx +0 -73
- package/src/widgets/DependenciesEditor.tsx +0 -56
- package/src/widgets/EnumEditor.tsx +0 -66
- package/src/widgets/ExpressionBuilder.tsx +0 -509
- package/src/widgets/ExpressionSwitch.tsx +0 -62
- package/src/widgets/OptionsEditor.tsx +0 -141
- package/src/widgets/ReactionsEditor.tsx +0 -532
- package/src/widgets/RemoteDataEditor.tsx +0 -382
- package/src/widgets/ValidateEditor.tsx +0 -162
- package/src/widgets/expressionModel.test.ts +0 -262
- package/src/widgets/expressionModel.ts +0 -573
- package/src/widgets/index.ts +0 -45
- package/src/widgets/reactionsModel.ts +0 -190
- package/src/widgets/useFormDataFields.ts +0 -21
- /package/dist/es/{form-engine-designer.css → index.css} +0 -0
|
@@ -1,52 +1,52 @@
|
|
|
1
1
|
import { jsx as i, jsxs as d } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
import { useState as
|
|
2
|
+
import { Space as p, Input as h, Select as K, Tooltip as u, Collapse as k, InputNumber as S, Button as y } from "antd";
|
|
3
|
+
import { useState as C, useRef as f, useEffect as P } from "react";
|
|
4
4
|
import { genId as x } from "./reactionsModel.js";
|
|
5
5
|
function v(e) {
|
|
6
|
-
return !e || typeof e != "object" ? [] : Object.entries(e).map(([
|
|
6
|
+
return !e || typeof e != "object" ? [] : Object.entries(e).map(([l, t]) => ({
|
|
7
7
|
id: x(),
|
|
8
|
-
key:
|
|
9
|
-
value: typeof
|
|
8
|
+
key: l,
|
|
9
|
+
value: typeof t == "string" ? t : JSON.stringify(t)
|
|
10
10
|
}));
|
|
11
11
|
}
|
|
12
12
|
function g(e) {
|
|
13
13
|
if (!e)
|
|
14
14
|
return;
|
|
15
|
-
const
|
|
16
|
-
for (const
|
|
17
|
-
const
|
|
18
|
-
if (!
|
|
15
|
+
const l = {};
|
|
16
|
+
for (const t of e) {
|
|
17
|
+
const n = t.key.trim();
|
|
18
|
+
if (!n)
|
|
19
19
|
continue;
|
|
20
|
-
const r =
|
|
20
|
+
const r = t.value.trim();
|
|
21
21
|
if (r)
|
|
22
22
|
try {
|
|
23
|
-
|
|
23
|
+
l[n] = JSON.parse(r);
|
|
24
24
|
} catch {
|
|
25
|
-
|
|
25
|
+
l[n] = r;
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
-
return Object.keys(
|
|
28
|
+
return Object.keys(l).length > 0 ? l : void 0;
|
|
29
29
|
}
|
|
30
30
|
function b(e) {
|
|
31
|
-
const
|
|
31
|
+
const l = e ?? {}, t = l.responseField ?? {}, n = l.params;
|
|
32
32
|
return {
|
|
33
|
-
url:
|
|
34
|
-
method:
|
|
35
|
-
dataPath:
|
|
36
|
-
valueKey:
|
|
37
|
-
labelKey:
|
|
38
|
-
params:
|
|
39
|
-
headers: v(
|
|
40
|
-
cacheKey:
|
|
41
|
-
timeout:
|
|
33
|
+
url: l.url,
|
|
34
|
+
method: l.method,
|
|
35
|
+
dataPath: t.data,
|
|
36
|
+
valueKey: t.value,
|
|
37
|
+
labelKey: t.label,
|
|
38
|
+
params: n && typeof n == "object" ? v(n) : void 0,
|
|
39
|
+
headers: v(l.headers),
|
|
40
|
+
cacheKey: l.cacheKey,
|
|
41
|
+
timeout: l.timeout
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
|
-
function
|
|
45
|
-
const
|
|
46
|
-
if (!
|
|
44
|
+
function T(e) {
|
|
45
|
+
const l = e.url?.trim();
|
|
46
|
+
if (!l)
|
|
47
47
|
return;
|
|
48
|
-
const
|
|
49
|
-
url:
|
|
48
|
+
const t = g(e.params), n = g(e.headers), r = {
|
|
49
|
+
url: l,
|
|
50
50
|
method: e.method || "GET",
|
|
51
51
|
responseField: {
|
|
52
52
|
data: e.dataPath?.trim() || "data",
|
|
@@ -54,13 +54,13 @@ function w(e) {
|
|
|
54
54
|
label: e.labelKey?.trim() || "label"
|
|
55
55
|
}
|
|
56
56
|
};
|
|
57
|
-
return
|
|
57
|
+
return t && (r.params = t), n && (r.headers = n), e.cacheKey?.trim() && (r.cacheKey = e.cacheKey.trim()), e.timeout != null && (r.timeout = e.timeout), r;
|
|
58
58
|
}
|
|
59
59
|
function z({
|
|
60
60
|
rows: e,
|
|
61
|
-
onChange:
|
|
62
|
-
valuePlaceholder:
|
|
63
|
-
keyPlaceholder:
|
|
61
|
+
onChange: l,
|
|
62
|
+
valuePlaceholder: t,
|
|
63
|
+
keyPlaceholder: n
|
|
64
64
|
}) {
|
|
65
65
|
return /* @__PURE__ */ d("div", { style: { width: "100%" }, children: [
|
|
66
66
|
e.map((r) => /* @__PURE__ */ d(
|
|
@@ -78,8 +78,8 @@ function z({
|
|
|
78
78
|
{
|
|
79
79
|
size: "small",
|
|
80
80
|
value: r.key,
|
|
81
|
-
placeholder:
|
|
82
|
-
onChange: (c) =>
|
|
81
|
+
placeholder: n,
|
|
82
|
+
onChange: (c) => l(
|
|
83
83
|
e.map(
|
|
84
84
|
(o) => o.id === r.id ? { ...o, key: c.target.value } : o
|
|
85
85
|
)
|
|
@@ -91,8 +91,8 @@ function z({
|
|
|
91
91
|
{
|
|
92
92
|
size: "small",
|
|
93
93
|
value: r.value,
|
|
94
|
-
placeholder:
|
|
95
|
-
onChange: (c) =>
|
|
94
|
+
placeholder: t,
|
|
95
|
+
onChange: (c) => l(
|
|
96
96
|
e.map(
|
|
97
97
|
(o) => o.id === r.id ? { ...o, value: c.target.value } : o
|
|
98
98
|
)
|
|
@@ -105,7 +105,7 @@ function z({
|
|
|
105
105
|
size: "small",
|
|
106
106
|
type: "text",
|
|
107
107
|
danger: !0,
|
|
108
|
-
onClick: () =>
|
|
108
|
+
onClick: () => l(e.filter((c) => c.id !== r.id)),
|
|
109
109
|
children: "✕"
|
|
110
110
|
}
|
|
111
111
|
)
|
|
@@ -119,42 +119,42 @@ function z({
|
|
|
119
119
|
size: "small",
|
|
120
120
|
type: "dashed",
|
|
121
121
|
block: !0,
|
|
122
|
-
onClick: () =>
|
|
122
|
+
onClick: () => l([...e, { id: x(), key: "", value: "" }]),
|
|
123
123
|
children: "+ 添加"
|
|
124
124
|
}
|
|
125
125
|
)
|
|
126
126
|
] });
|
|
127
127
|
}
|
|
128
|
-
function
|
|
129
|
-
const [
|
|
130
|
-
|
|
131
|
-
|
|
128
|
+
function w({ value: e, onChange: l }) {
|
|
129
|
+
const [t, n] = C(() => b(e)), r = f(e), c = f(e);
|
|
130
|
+
P(() => {
|
|
131
|
+
r.current !== e && (r.current = e, e !== c.current && n(b(e)));
|
|
132
132
|
}, [e]);
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
const m =
|
|
136
|
-
|
|
133
|
+
const o = (a) => {
|
|
134
|
+
n(a);
|
|
135
|
+
const m = T(a);
|
|
136
|
+
c.current = m, l(m);
|
|
137
137
|
}, s = (a) => {
|
|
138
|
-
|
|
138
|
+
o({ ...t, ...a });
|
|
139
139
|
};
|
|
140
|
-
return /* @__PURE__ */ i(
|
|
140
|
+
return /* @__PURE__ */ i("div", { style: { width: "100%" }, children: /* @__PURE__ */ d(p, { orientation: "vertical", style: { width: "100%" }, size: 8, children: [
|
|
141
141
|
/* @__PURE__ */ d("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
|
|
142
142
|
/* @__PURE__ */ i(
|
|
143
143
|
h,
|
|
144
144
|
{
|
|
145
145
|
size: "small",
|
|
146
146
|
placeholder: "接口地址(必填),如 /api/options",
|
|
147
|
-
value:
|
|
147
|
+
value: t.url,
|
|
148
148
|
onChange: (a) => s({ url: a.target.value }),
|
|
149
149
|
style: { flex: 1 }
|
|
150
150
|
}
|
|
151
151
|
),
|
|
152
152
|
/* @__PURE__ */ i(
|
|
153
|
-
|
|
153
|
+
K,
|
|
154
154
|
{
|
|
155
155
|
size: "small",
|
|
156
156
|
style: { width: 80 },
|
|
157
|
-
value:
|
|
157
|
+
value: t.method,
|
|
158
158
|
onChange: (a) => s({ method: a }),
|
|
159
159
|
options: [
|
|
160
160
|
{ value: "GET", label: "GET" },
|
|
@@ -170,7 +170,7 @@ function E({ value: e, onChange: t, title: n }) {
|
|
|
170
170
|
{
|
|
171
171
|
size: "small",
|
|
172
172
|
placeholder: "数据路径(默认 data)",
|
|
173
|
-
value:
|
|
173
|
+
value: t.dataPath,
|
|
174
174
|
onChange: (a) => s({ dataPath: a.target.value }),
|
|
175
175
|
style: { flex: 1 }
|
|
176
176
|
}
|
|
@@ -180,7 +180,7 @@ function E({ value: e, onChange: t, title: n }) {
|
|
|
180
180
|
{
|
|
181
181
|
size: "small",
|
|
182
182
|
placeholder: "值字段",
|
|
183
|
-
value:
|
|
183
|
+
value: t.valueKey,
|
|
184
184
|
onChange: (a) => s({ valueKey: a.target.value }),
|
|
185
185
|
style: { flex: 1 }
|
|
186
186
|
}
|
|
@@ -190,14 +190,14 @@ function E({ value: e, onChange: t, title: n }) {
|
|
|
190
190
|
{
|
|
191
191
|
size: "small",
|
|
192
192
|
placeholder: "文案字段",
|
|
193
|
-
value:
|
|
193
|
+
value: t.labelKey,
|
|
194
194
|
onChange: (a) => s({ labelKey: a.target.value }),
|
|
195
195
|
style: { flex: 1 }
|
|
196
196
|
}
|
|
197
197
|
) })
|
|
198
198
|
] }),
|
|
199
199
|
/* @__PURE__ */ i(
|
|
200
|
-
|
|
200
|
+
k,
|
|
201
201
|
{
|
|
202
202
|
size: "small",
|
|
203
203
|
style: { width: "100%", background: "#fafafa" },
|
|
@@ -208,7 +208,7 @@ function E({ value: e, onChange: t, title: n }) {
|
|
|
208
208
|
children: /* @__PURE__ */ i(
|
|
209
209
|
z,
|
|
210
210
|
{
|
|
211
|
-
rows:
|
|
211
|
+
rows: t.params ?? [],
|
|
212
212
|
onChange: (a) => s({ params: a }),
|
|
213
213
|
keyPlaceholder: "参数名",
|
|
214
214
|
valuePlaceholder: "参数值(数字/布尔自动识别)"
|
|
@@ -221,7 +221,7 @@ function E({ value: e, onChange: t, title: n }) {
|
|
|
221
221
|
children: /* @__PURE__ */ i(
|
|
222
222
|
z,
|
|
223
223
|
{
|
|
224
|
-
rows:
|
|
224
|
+
rows: t.headers ?? [],
|
|
225
225
|
onChange: (a) => s({ headers: a }),
|
|
226
226
|
keyPlaceholder: "请求头名",
|
|
227
227
|
valuePlaceholder: "如 Bearer xxxx"
|
|
@@ -259,7 +259,7 @@ function E({ value: e, onChange: t, title: n }) {
|
|
|
259
259
|
{
|
|
260
260
|
size: "small",
|
|
261
261
|
placeholder: "默认按字段路径缓存",
|
|
262
|
-
value:
|
|
262
|
+
value: t.cacheKey,
|
|
263
263
|
onChange: (a) => s({ cacheKey: a.target.value })
|
|
264
264
|
}
|
|
265
265
|
)
|
|
@@ -283,11 +283,11 @@ function E({ value: e, onChange: t, title: n }) {
|
|
|
283
283
|
}
|
|
284
284
|
),
|
|
285
285
|
/* @__PURE__ */ i(
|
|
286
|
-
|
|
286
|
+
S,
|
|
287
287
|
{
|
|
288
288
|
size: "small",
|
|
289
289
|
min: 1,
|
|
290
|
-
value:
|
|
290
|
+
value: t.timeout,
|
|
291
291
|
onChange: (a) => s({ timeout: a ?? void 0 }),
|
|
292
292
|
placeholder: "默认 10",
|
|
293
293
|
style: { width: 120 }
|
|
@@ -306,9 +306,9 @@ function E({ value: e, onChange: t, title: n }) {
|
|
|
306
306
|
/* @__PURE__ */ i("div", { style: { fontSize: 11, color: "#ccc" }, children: "提示:字段值变化后选项自动刷新;POST 时参数放入请求体" })
|
|
307
307
|
] }) });
|
|
308
308
|
}
|
|
309
|
-
const
|
|
309
|
+
const j = w;
|
|
310
310
|
export {
|
|
311
|
-
|
|
312
|
-
|
|
311
|
+
w as RemoteDataEditor,
|
|
312
|
+
j as remoteDataEditorWidget
|
|
313
313
|
};
|
|
314
314
|
//# sourceMappingURL=RemoteDataEditor.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RemoteDataEditor.js","sources":["../../../src/widgets/RemoteDataEditor.tsx"],"sourcesContent":["// ============================================================================\n// RemoteDataEditor — 可视化编辑 remoteData 远程数据配置\n// 表单化配置代替手写 JSON:\n// - 接口地址 / 请求方式(GET | POST)\n// - 响应字段映射(数据数组路径 / 值字段 / 文案字段)\n// - 请求参数(key-value 行编辑)\n// - 请求头(key-value 行编辑,可选)\n// - 缓存键 / 超时(可选)\n// 值格式:RemoteDataConfig(见 @xbeeant/form-engine-ui 的 _shared.tsx)\n// ============================================================================\n\nimport type { WidgetProps } from '@xbeeant/form-engine-ui';\nimport {\n Button,\n Collapse,\n Form,\n Input,\n InputNumber,\n Select,\n Space,\n Tooltip,\n} from 'antd';\nimport { useEffect, useRef, useState } from 'react';\nimport { genId } from './reactionsModel';\n\ninterface KeyValueRow {\n id: string;\n key: string;\n value: string;\n}\n\ninterface RemoteDataForm {\n url?: string;\n method?: 'GET' | 'POST';\n dataPath?: string;\n valueKey?: string;\n labelKey?: string;\n params?: KeyValueRow[];\n headers?: KeyValueRow[];\n cacheKey?: string;\n timeout?: number;\n}\n\n/** Record → key-value 行 */\nfunction recordToRows(\n value: Record<string, unknown> | undefined,\n): KeyValueRow[] {\n if (!value || typeof value !== 'object') {\n return [];\n }\n return Object.entries(value).map(([key, v]) => ({\n id: genId(),\n key,\n value: typeof v === 'string' ? v : JSON.stringify(v),\n }));\n}\n\n/** key-value 行 → Record(空 key 或空 value 的行丢弃) */\nfunction rowsToRecord(\n rows: KeyValueRow[] | undefined,\n): Record<string, unknown> | undefined {\n if (!rows) {\n return undefined;\n }\n const result: Record<string, unknown> = {};\n for (const row of rows) {\n const key = row.key.trim();\n if (!key) {\n continue;\n }\n const raw = row.value.trim();\n if (!raw) {\n continue;\n }\n // 尝试解析 JSON(数字 / 布尔 / 对象),失败保留字符串\n try {\n result[key] = JSON.parse(raw);\n } catch {\n result[key] = raw;\n }\n }\n return Object.keys(result).length > 0 ? result : undefined;\n}\n\n/** RemoteDataConfig → 表单 */\nfunction configToForm(value: unknown): RemoteDataForm {\n const cfg = (value ?? {}) as Record<string, any>;\n const rf = (cfg.responseField ?? {}) as Record<string, any>;\n const params = cfg.params;\n return {\n url: cfg.url,\n method: cfg.method,\n dataPath: rf.data,\n valueKey: rf.value,\n labelKey: rf.label,\n params:\n params && typeof params === 'object' ? recordToRows(params) : undefined,\n headers: recordToRows(cfg.headers),\n cacheKey: cfg.cacheKey,\n timeout: cfg.timeout,\n };\n}\n\n/** 表单 → RemoteDataConfig */\nfunction formToConfig(\n form: RemoteDataForm,\n): Record<string, unknown> | undefined {\n const url = form.url?.trim();\n if (!url) {\n return undefined;\n }\n const params = rowsToRecord(form.params);\n const headers = rowsToRecord(form.headers);\n const config: Record<string, unknown> = {\n url,\n method: form.method || 'GET',\n responseField: {\n data: form.dataPath?.trim() || 'data',\n value: form.valueKey?.trim() || 'value',\n label: form.labelKey?.trim() || 'label',\n },\n };\n if (params) {\n config.params = params;\n }\n if (headers) {\n config.headers = headers;\n }\n if (form.cacheKey?.trim()) {\n config.cacheKey = form.cacheKey.trim();\n }\n if (form.timeout != null) {\n config.timeout = form.timeout;\n }\n return config;\n}\n\n/** key-value 行编辑器(参数 / 请求头共用) */\nfunction KeyValueRows({\n rows,\n onChange,\n valuePlaceholder,\n keyPlaceholder,\n}: {\n rows: KeyValueRow[];\n onChange: (rows: KeyValueRow[]) => void;\n valuePlaceholder: string;\n keyPlaceholder: string;\n}) {\n return (\n <div style={{ width: '100%' }}>\n {rows.map((row) => (\n <div\n key={row.id}\n style={{\n display: 'flex',\n gap: 6,\n alignItems: 'center',\n marginBottom: 6,\n }}\n >\n <Input\n size='small'\n value={row.key}\n placeholder={keyPlaceholder}\n onChange={(e) =>\n onChange(\n rows.map((r) =>\n r.id === row.id ? { ...r, key: e.target.value } : r,\n ),\n )\n }\n />\n <Input\n size='small'\n value={row.value}\n placeholder={valuePlaceholder}\n onChange={(e) =>\n onChange(\n rows.map((r) =>\n r.id === row.id ? { ...r, value: e.target.value } : r,\n ),\n )\n }\n />\n <Button\n size='small'\n type='text'\n danger\n onClick={() => onChange(rows.filter((r) => r.id !== row.id))}\n >\n ✕\n </Button>\n </div>\n ))}\n <Button\n size='small'\n type='dashed'\n block\n onClick={() => onChange([...rows, { id: genId(), key: '', value: '' }])}\n >\n + 添加\n </Button>\n </div>\n );\n}\n\nexport function RemoteDataEditor({ value, onChange, title }: WidgetProps) {\n const [form, setForm] = useState<RemoteDataForm>(() => configToForm(value));\n const prevValueRef = useRef(value);\n // 自身 onChange 引发的 value 回传不应触发重建(否则每次输入都被重置)\n const lastEmittedRef = useRef(value);\n\n useEffect(() => {\n if (prevValueRef.current !== value) {\n prevValueRef.current = value;\n if (value !== lastEmittedRef.current) {\n setForm(configToForm(value));\n }\n }\n }, [value]);\n\n const commit = (next: RemoteDataForm) => {\n setForm(next);\n const emitted = formToConfig(next);\n lastEmittedRef.current = emitted;\n onChange(emitted);\n };\n\n const patch = (partial: Partial<RemoteDataForm>) => {\n commit({ ...form, ...partial });\n };\n\n return (\n <Form.Item layout={'vertical'} label={title} style={{ width: '100%' }}>\n <Space orientation='vertical' style={{ width: '100%' }} size={8}>\n {/* 请求地址 + 方式 */}\n <div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>\n <Input\n size='small'\n placeholder='接口地址(必填),如 /api/options'\n value={form.url}\n onChange={(e) => patch({ url: e.target.value })}\n style={{ flex: 1 }}\n />\n <Select\n size='small'\n style={{ width: 80 }}\n value={form.method}\n onChange={(v) => patch({ method: v })}\n options={[\n { value: 'GET', label: 'GET' },\n { value: 'POST', label: 'POST' },\n ]}\n />\n </div>\n\n {/* 响应字段映射 */}\n <div style={{ fontSize: 11, color: '#999' }}>响应字段映射</div>\n <div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>\n <Tooltip title='响应数据数组的路径,如 data.list / data.result.records'>\n <Input\n size='small'\n placeholder='数据路径(默认 data)'\n value={form.dataPath}\n onChange={(e) => patch({ dataPath: e.target.value })}\n style={{ flex: 1 }}\n />\n </Tooltip>\n <Tooltip title='作为选项值(value)的字段名'>\n <Input\n size='small'\n placeholder='值字段'\n value={form.valueKey}\n onChange={(e) => patch({ valueKey: e.target.value })}\n style={{ flex: 1 }}\n />\n </Tooltip>\n <Tooltip title='作为选项文案(label)的字段名'>\n <Input\n size='small'\n placeholder='文案字段'\n value={form.labelKey}\n onChange={(e) => patch({ labelKey: e.target.value })}\n style={{ flex: 1 }}\n />\n </Tooltip>\n </div>\n\n {/* 请求参数 / 请求头 / 高级 */}\n <Collapse\n size='small'\n style={{ width: '100%', background: '#fafafa' }}\n items={[\n {\n key: 'params',\n label: '请求参数(可选)',\n children: (\n <KeyValueRows\n rows={form.params ?? []}\n onChange={(rows) => patch({ params: rows })}\n keyPlaceholder='参数名'\n valuePlaceholder='参数值(数字/布尔自动识别)'\n />\n ),\n },\n {\n key: 'headers',\n label: '请求头(可选)',\n children: (\n <KeyValueRows\n rows={form.headers ?? []}\n onChange={(rows) => patch({ headers: rows })}\n keyPlaceholder='请求头名'\n valuePlaceholder='如 Bearer xxxx'\n />\n ),\n },\n {\n key: 'advanced',\n label: '高级',\n children: (\n <Space\n orientation='vertical'\n style={{ width: '100%' }}\n size={8}\n >\n <div\n style={{ display: 'flex', gap: 6, alignItems: 'center' }}\n >\n <span\n style={{\n fontSize: 12,\n color: '#666',\n whiteSpace: 'nowrap',\n }}\n >\n 缓存键\n </span>\n <Input\n size='small'\n placeholder='默认按字段路径缓存'\n value={form.cacheKey}\n onChange={(e) => patch({ cacheKey: e.target.value })}\n />\n </div>\n <div\n style={{ display: 'flex', gap: 6, alignItems: 'center' }}\n >\n <span\n style={{\n fontSize: 12,\n color: '#666',\n whiteSpace: 'nowrap',\n }}\n >\n 超时(秒)\n </span>\n <InputNumber\n size='small'\n min={1}\n value={form.timeout}\n onChange={(v) => patch({ timeout: v ?? undefined })}\n placeholder='默认 10'\n style={{ width: 120 }}\n />\n </div>\n </Space>\n ),\n },\n ]}\n />\n\n <div style={{ fontSize: 11, color: '#ccc' }}>\n 提示:字段值变化后选项自动刷新;POST 时参数放入请求体\n </div>\n </Space>\n </Form.Item>\n );\n}\n\nexport const remoteDataEditorWidget = RemoteDataEditor;\n"],"names":["recordToRows","value","key","v","genId","rowsToRecord","rows","result","row","raw","configToForm","cfg","rf","params","formToConfig","form","url","headers","config","KeyValueRows","onChange","valuePlaceholder","keyPlaceholder","jsxs","jsx","Input","e","r","Button","RemoteDataEditor","title","setForm","useState","prevValueRef","useRef","lastEmittedRef","useEffect","commit","next","emitted","patch","partial","Form","Space","Select","Tooltip","Collapse","InputNumber","remoteDataEditorWidget"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"RemoteDataEditor.js","sources":["../../../src/widgets/RemoteDataEditor.tsx"],"sourcesContent":["// ============================================================================\n// RemoteDataEditor — 可视化编辑 remoteData 远程数据配置\n// 表单化配置代替手写 JSON:\n// - 接口地址 / 请求方式(GET | POST)\n// - 响应字段映射(数据数组路径 / 值字段 / 文案字段)\n// - 请求参数(key-value 行编辑)\n// - 请求头(key-value 行编辑,可选)\n// - 缓存键 / 超时(可选)\n// 值格式:RemoteDataConfig(见 @xbeeant/form-engine-ui 的 _shared.tsx)\n// ============================================================================\n\nimport type { WidgetProps } from '@xbeeant/form-engine-ui';\nimport {\n Button,\n Collapse,\n Input,\n InputNumber,\n Select,\n Space,\n Tooltip,\n} from 'antd';\nimport { useEffect, useRef, useState } from 'react';\nimport { genId } from './reactionsModel';\n\ninterface KeyValueRow {\n id: string;\n key: string;\n value: string;\n}\n\ninterface RemoteDataForm {\n url?: string;\n method?: 'GET' | 'POST';\n dataPath?: string;\n valueKey?: string;\n labelKey?: string;\n params?: KeyValueRow[];\n headers?: KeyValueRow[];\n cacheKey?: string;\n timeout?: number;\n}\n\n/** Record → key-value 行 */\nfunction recordToRows(\n value: Record<string, unknown> | undefined,\n): KeyValueRow[] {\n if (!value || typeof value !== 'object') {\n return [];\n }\n return Object.entries(value).map(([key, v]) => ({\n id: genId(),\n key,\n value: typeof v === 'string' ? v : JSON.stringify(v),\n }));\n}\n\n/** key-value 行 → Record(空 key 或空 value 的行丢弃) */\nfunction rowsToRecord(\n rows: KeyValueRow[] | undefined,\n): Record<string, unknown> | undefined {\n if (!rows) {\n return undefined;\n }\n const result: Record<string, unknown> = {};\n for (const row of rows) {\n const key = row.key.trim();\n if (!key) {\n continue;\n }\n const raw = row.value.trim();\n if (!raw) {\n continue;\n }\n // 尝试解析 JSON(数字 / 布尔 / 对象),失败保留字符串\n try {\n result[key] = JSON.parse(raw);\n } catch {\n result[key] = raw;\n }\n }\n return Object.keys(result).length > 0 ? result : undefined;\n}\n\n/** RemoteDataConfig → 表单 */\nfunction configToForm(value: unknown): RemoteDataForm {\n const cfg = (value ?? {}) as Record<string, any>;\n const rf = (cfg.responseField ?? {}) as Record<string, any>;\n const params = cfg.params;\n return {\n url: cfg.url,\n method: cfg.method,\n dataPath: rf.data,\n valueKey: rf.value,\n labelKey: rf.label,\n params:\n params && typeof params === 'object' ? recordToRows(params) : undefined,\n headers: recordToRows(cfg.headers),\n cacheKey: cfg.cacheKey,\n timeout: cfg.timeout,\n };\n}\n\n/** 表单 → RemoteDataConfig */\nfunction formToConfig(\n form: RemoteDataForm,\n): Record<string, unknown> | undefined {\n const url = form.url?.trim();\n if (!url) {\n return undefined;\n }\n const params = rowsToRecord(form.params);\n const headers = rowsToRecord(form.headers);\n const config: Record<string, unknown> = {\n url,\n method: form.method || 'GET',\n responseField: {\n data: form.dataPath?.trim() || 'data',\n value: form.valueKey?.trim() || 'value',\n label: form.labelKey?.trim() || 'label',\n },\n };\n if (params) {\n config.params = params;\n }\n if (headers) {\n config.headers = headers;\n }\n if (form.cacheKey?.trim()) {\n config.cacheKey = form.cacheKey.trim();\n }\n if (form.timeout != null) {\n config.timeout = form.timeout;\n }\n return config;\n}\n\n/** key-value 行编辑器(参数 / 请求头共用) */\nfunction KeyValueRows({\n rows,\n onChange,\n valuePlaceholder,\n keyPlaceholder,\n}: {\n rows: KeyValueRow[];\n onChange: (rows: KeyValueRow[]) => void;\n valuePlaceholder: string;\n keyPlaceholder: string;\n}) {\n return (\n <div style={{ width: '100%' }}>\n {rows.map((row) => (\n <div\n key={row.id}\n style={{\n display: 'flex',\n gap: 6,\n alignItems: 'center',\n marginBottom: 6,\n }}\n >\n <Input\n size='small'\n value={row.key}\n placeholder={keyPlaceholder}\n onChange={(e) =>\n onChange(\n rows.map((r) =>\n r.id === row.id ? { ...r, key: e.target.value } : r,\n ),\n )\n }\n />\n <Input\n size='small'\n value={row.value}\n placeholder={valuePlaceholder}\n onChange={(e) =>\n onChange(\n rows.map((r) =>\n r.id === row.id ? { ...r, value: e.target.value } : r,\n ),\n )\n }\n />\n <Button\n size='small'\n type='text'\n danger\n onClick={() => onChange(rows.filter((r) => r.id !== row.id))}\n >\n ✕\n </Button>\n </div>\n ))}\n <Button\n size='small'\n type='dashed'\n block\n onClick={() => onChange([...rows, { id: genId(), key: '', value: '' }])}\n >\n + 添加\n </Button>\n </div>\n );\n}\n\nexport function RemoteDataEditor({ value, onChange }: WidgetProps) {\n const [form, setForm] = useState<RemoteDataForm>(() => configToForm(value));\n const prevValueRef = useRef(value);\n // 自身 onChange 引发的 value 回传不应触发重建(否则每次输入都被重置)\n const lastEmittedRef = useRef(value);\n\n useEffect(() => {\n if (prevValueRef.current !== value) {\n prevValueRef.current = value;\n if (value !== lastEmittedRef.current) {\n setForm(configToForm(value));\n }\n }\n }, [value]);\n\n const commit = (next: RemoteDataForm) => {\n setForm(next);\n const emitted = formToConfig(next);\n lastEmittedRef.current = emitted;\n onChange(emitted);\n };\n\n const patch = (partial: Partial<RemoteDataForm>) => {\n commit({ ...form, ...partial });\n };\n\n return (\n <div style={{ width: '100%' }}>\n <Space orientation='vertical' style={{ width: '100%' }} size={8}>\n {/* 请求地址 + 方式 */}\n <div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>\n <Input\n size='small'\n placeholder='接口地址(必填),如 /api/options'\n value={form.url}\n onChange={(e) => patch({ url: e.target.value })}\n style={{ flex: 1 }}\n />\n <Select\n size='small'\n style={{ width: 80 }}\n value={form.method}\n onChange={(v) => patch({ method: v })}\n options={[\n { value: 'GET', label: 'GET' },\n { value: 'POST', label: 'POST' },\n ]}\n />\n </div>\n\n {/* 响应字段映射 */}\n <div style={{ fontSize: 11, color: '#999' }}>响应字段映射</div>\n <div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>\n <Tooltip title='响应数据数组的路径,如 data.list / data.result.records'>\n <Input\n size='small'\n placeholder='数据路径(默认 data)'\n value={form.dataPath}\n onChange={(e) => patch({ dataPath: e.target.value })}\n style={{ flex: 1 }}\n />\n </Tooltip>\n <Tooltip title='作为选项值(value)的字段名'>\n <Input\n size='small'\n placeholder='值字段'\n value={form.valueKey}\n onChange={(e) => patch({ valueKey: e.target.value })}\n style={{ flex: 1 }}\n />\n </Tooltip>\n <Tooltip title='作为选项文案(label)的字段名'>\n <Input\n size='small'\n placeholder='文案字段'\n value={form.labelKey}\n onChange={(e) => patch({ labelKey: e.target.value })}\n style={{ flex: 1 }}\n />\n </Tooltip>\n </div>\n\n {/* 请求参数 / 请求头 / 高级 */}\n <Collapse\n size='small'\n style={{ width: '100%', background: '#fafafa' }}\n items={[\n {\n key: 'params',\n label: '请求参数(可选)',\n children: (\n <KeyValueRows\n rows={form.params ?? []}\n onChange={(rows) => patch({ params: rows })}\n keyPlaceholder='参数名'\n valuePlaceholder='参数值(数字/布尔自动识别)'\n />\n ),\n },\n {\n key: 'headers',\n label: '请求头(可选)',\n children: (\n <KeyValueRows\n rows={form.headers ?? []}\n onChange={(rows) => patch({ headers: rows })}\n keyPlaceholder='请求头名'\n valuePlaceholder='如 Bearer xxxx'\n />\n ),\n },\n {\n key: 'advanced',\n label: '高级',\n children: (\n <Space\n orientation='vertical'\n style={{ width: '100%' }}\n size={8}\n >\n <div\n style={{ display: 'flex', gap: 6, alignItems: 'center' }}\n >\n <span\n style={{\n fontSize: 12,\n color: '#666',\n whiteSpace: 'nowrap',\n }}\n >\n 缓存键\n </span>\n <Input\n size='small'\n placeholder='默认按字段路径缓存'\n value={form.cacheKey}\n onChange={(e) => patch({ cacheKey: e.target.value })}\n />\n </div>\n <div\n style={{ display: 'flex', gap: 6, alignItems: 'center' }}\n >\n <span\n style={{\n fontSize: 12,\n color: '#666',\n whiteSpace: 'nowrap',\n }}\n >\n 超时(秒)\n </span>\n <InputNumber\n size='small'\n min={1}\n value={form.timeout}\n onChange={(v) => patch({ timeout: v ?? undefined })}\n placeholder='默认 10'\n style={{ width: 120 }}\n />\n </div>\n </Space>\n ),\n },\n ]}\n />\n\n <div style={{ fontSize: 11, color: '#ccc' }}>\n 提示:字段值变化后选项自动刷新;POST 时参数放入请求体\n </div>\n </Space>\n </div>\n );\n}\n\nexport const remoteDataEditorWidget = RemoteDataEditor;\n"],"names":["recordToRows","value","key","v","genId","rowsToRecord","rows","result","row","raw","configToForm","cfg","rf","params","formToConfig","form","url","headers","config","KeyValueRows","onChange","valuePlaceholder","keyPlaceholder","jsxs","jsx","Input","e","r","Button","RemoteDataEditor","setForm","useState","prevValueRef","useRef","lastEmittedRef","useEffect","commit","next","emitted","patch","partial","Space","Select","Tooltip","Collapse","InputNumber","remoteDataEditorWidget"],"mappings":"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"}
|
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
import {
|
|
3
|
-
import { useState as
|
|
4
|
-
import { ExpressionBuilder as
|
|
5
|
-
import { genId as
|
|
6
|
-
import { useFormDataFields as
|
|
7
|
-
function
|
|
1
|
+
import { jsxs as c, jsx as r } from "react/jsx-runtime";
|
|
2
|
+
import { Button as u, Input as k } from "antd";
|
|
3
|
+
import { useState as v, useRef as h, useEffect as R } from "react";
|
|
4
|
+
import { ExpressionBuilder as z } from "./ExpressionBuilder.js";
|
|
5
|
+
import { genId as y } from "./reactionsModel.js";
|
|
6
|
+
import { useFormDataFields as B } from "./useFormDataFields.js";
|
|
7
|
+
function g(e) {
|
|
8
8
|
return !e || typeof e != "object" ? [] : Object.entries(e).map(
|
|
9
|
-
([n,
|
|
9
|
+
([n, s]) => ({ id: y(), key: n, expr: String(s ?? "") })
|
|
10
10
|
);
|
|
11
11
|
}
|
|
12
|
-
function
|
|
12
|
+
function S(e) {
|
|
13
13
|
const n = {};
|
|
14
|
-
for (const
|
|
15
|
-
const
|
|
16
|
-
!
|
|
14
|
+
for (const s of e) {
|
|
15
|
+
const o = s.key.trim(), l = s.expr.trim();
|
|
16
|
+
!o || !l || l === "{{ }}" || (n[o] = l);
|
|
17
17
|
}
|
|
18
18
|
return Object.keys(n).length > 0 ? n : void 0;
|
|
19
19
|
}
|
|
20
|
-
function
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
function j({ value: e, onChange: n }) {
|
|
21
|
+
const s = B(), [o, l] = v(() => g(e)), m = h(e), f = h(e);
|
|
22
|
+
R(() => {
|
|
23
|
+
m.current !== e && (m.current = e, e !== f.current && l(g(e)));
|
|
24
24
|
}, [e]);
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
},
|
|
30
|
-
|
|
31
|
-
},
|
|
32
|
-
|
|
33
|
-
},
|
|
34
|
-
|
|
25
|
+
const a = (t) => {
|
|
26
|
+
l(t);
|
|
27
|
+
const i = S(t);
|
|
28
|
+
f.current = i, n(i);
|
|
29
|
+
}, p = (t, i) => {
|
|
30
|
+
a(o.map((d) => d.id === t ? { ...d, ...i } : d));
|
|
31
|
+
}, x = (t) => {
|
|
32
|
+
a(o.filter((i) => i.id !== t));
|
|
33
|
+
}, b = () => {
|
|
34
|
+
a([...o, { id: y(), key: "", expr: "{{ }}" }]);
|
|
35
35
|
};
|
|
36
|
-
return /* @__PURE__ */
|
|
37
|
-
o.length === 0 ? /* @__PURE__ */
|
|
36
|
+
return /* @__PURE__ */ c("div", { style: { width: "100%" }, children: [
|
|
37
|
+
o.length === 0 ? /* @__PURE__ */ r(
|
|
38
38
|
"div",
|
|
39
39
|
{
|
|
40
40
|
style: {
|
|
@@ -48,7 +48,7 @@ function C({ value: e, onChange: n, title: l }) {
|
|
|
48
48
|
},
|
|
49
49
|
children: "点击下方「添加校验规则」,组合 校验名称 + 表达式(变量 / 操作符 / 值)。表达式需返回 boolean,可用变量:$self.value、formData。"
|
|
50
50
|
}
|
|
51
|
-
) : o.map((t,
|
|
51
|
+
) : o.map((t, i) => /* @__PURE__ */ c(
|
|
52
52
|
"div",
|
|
53
53
|
{
|
|
54
54
|
style: {
|
|
@@ -59,7 +59,7 @@ function C({ value: e, onChange: n, title: l }) {
|
|
|
59
59
|
background: "#fff"
|
|
60
60
|
},
|
|
61
61
|
children: [
|
|
62
|
-
/* @__PURE__ */
|
|
62
|
+
/* @__PURE__ */ c(
|
|
63
63
|
"div",
|
|
64
64
|
{
|
|
65
65
|
style: {
|
|
@@ -69,34 +69,34 @@ function C({ value: e, onChange: n, title: l }) {
|
|
|
69
69
|
marginBottom: 6
|
|
70
70
|
},
|
|
71
71
|
children: [
|
|
72
|
-
/* @__PURE__ */
|
|
72
|
+
/* @__PURE__ */ c("span", { style: { fontSize: 12, fontWeight: 600, color: "#333" }, children: [
|
|
73
73
|
"校验规则 ",
|
|
74
|
-
|
|
74
|
+
i + 1
|
|
75
75
|
] }),
|
|
76
|
-
/* @__PURE__ */
|
|
76
|
+
/* @__PURE__ */ r(u, { size: "small", danger: !0, onClick: () => x(t.id), children: "删除" })
|
|
77
77
|
]
|
|
78
78
|
}
|
|
79
79
|
),
|
|
80
|
-
/* @__PURE__ */
|
|
81
|
-
/* @__PURE__ */
|
|
82
|
-
/* @__PURE__ */
|
|
83
|
-
|
|
80
|
+
/* @__PURE__ */ c("div", { style: { marginBottom: 6 }, children: [
|
|
81
|
+
/* @__PURE__ */ r("div", { style: { fontSize: 11, color: "#666", marginBottom: 2 }, children: "规则名称(key)" }),
|
|
82
|
+
/* @__PURE__ */ r(
|
|
83
|
+
k,
|
|
84
84
|
{
|
|
85
85
|
size: "small",
|
|
86
86
|
placeholder: "如 match / len",
|
|
87
87
|
value: t.key,
|
|
88
|
-
onChange: (d) =>
|
|
88
|
+
onChange: (d) => p(t.id, { key: d.target.value })
|
|
89
89
|
}
|
|
90
90
|
)
|
|
91
91
|
] }),
|
|
92
|
-
/* @__PURE__ */
|
|
93
|
-
/* @__PURE__ */
|
|
94
|
-
/* @__PURE__ */
|
|
95
|
-
|
|
92
|
+
/* @__PURE__ */ c("div", { children: [
|
|
93
|
+
/* @__PURE__ */ r("div", { style: { fontSize: 11, color: "#666", marginBottom: 2 }, children: "校验表达式(需返回 boolean)" }),
|
|
94
|
+
/* @__PURE__ */ r(
|
|
95
|
+
z,
|
|
96
96
|
{
|
|
97
97
|
value: t.expr,
|
|
98
|
-
onChange: (d) =>
|
|
99
|
-
fields:
|
|
98
|
+
onChange: (d) => p(t.id, { expr: d }),
|
|
99
|
+
fields: s,
|
|
100
100
|
showSelf: !0,
|
|
101
101
|
placeholder: "{{ $self.value.length >= 6 }}"
|
|
102
102
|
}
|
|
@@ -106,13 +106,13 @@ function C({ value: e, onChange: n, title: l }) {
|
|
|
106
106
|
},
|
|
107
107
|
t.id
|
|
108
108
|
)),
|
|
109
|
-
/* @__PURE__ */
|
|
110
|
-
/* @__PURE__ */
|
|
109
|
+
/* @__PURE__ */ r(u, { size: "small", type: "dashed", block: !0, onClick: b, children: "+ 添加校验规则" }),
|
|
110
|
+
/* @__PURE__ */ r("div", { style: { fontSize: 11, color: "#999", marginTop: 4 }, children: "提示:依赖字段(formData.xxx)变化时会自动联动重校验。" })
|
|
111
111
|
] });
|
|
112
112
|
}
|
|
113
|
-
const
|
|
113
|
+
const V = j;
|
|
114
114
|
export {
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
j as ValidateEditor,
|
|
116
|
+
V as validateEditorWidget
|
|
117
117
|
};
|
|
118
118
|
//# sourceMappingURL=ValidateEditor.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ValidateEditor.js","sources":["../../../src/widgets/ValidateEditor.tsx"],"sourcesContent":["// ============================================================================\n// ValidateEditor — 可视化编辑 validate 校验规则\n// 每行一条规则:「规则名称 + 校验表达式」(表达式需返回 boolean)\n// 与 schema 的 ValidateSchema({ key: Expression })互相转换\n// ============================================================================\n\nimport type { WidgetProps } from '@xbeeant/form-engine-ui';\nimport { Button,
|
|
1
|
+
{"version":3,"file":"ValidateEditor.js","sources":["../../../src/widgets/ValidateEditor.tsx"],"sourcesContent":["// ============================================================================\n// ValidateEditor — 可视化编辑 validate 校验规则\n// 每行一条规则:「规则名称 + 校验表达式」(表达式需返回 boolean)\n// 与 schema 的 ValidateSchema({ key: Expression })互相转换\n// ============================================================================\n\nimport type { WidgetProps } from '@xbeeant/form-engine-ui';\nimport { Button, Input } from 'antd';\nimport { useEffect, useRef, useState } from 'react';\nimport { ExpressionBuilder } from './ExpressionBuilder';\nimport { genId } from './reactionsModel';\nimport { useFormDataFields } from './useFormDataFields';\n\ninterface ValidateRow {\n id: string;\n key: string;\n expr: string;\n}\n\n/** ValidateSchema 对象 → 规则行 */\nfunction validateToRows(value: unknown): ValidateRow[] {\n if (!value || typeof value !== 'object') {\n return [];\n }\n return Object.entries(value as Record<string, unknown>).map(\n ([key, expr]) => ({ id: genId(), key, expr: String(expr ?? '') }),\n );\n}\n\n/** 规则行 → ValidateSchema 对象(空表达式 / 空 key 的行丢弃) */\nfunction rowsToValidate(\n rows: ValidateRow[],\n): Record<string, string> | undefined {\n const result: Record<string, string> = {};\n for (const row of rows) {\n const key = row.key.trim();\n const expr = row.expr.trim();\n if (!key || !expr || expr === '{{ }}') {\n continue;\n }\n result[key] = expr;\n }\n return Object.keys(result).length > 0 ? result : undefined;\n}\n\nexport function ValidateEditor({ value, onChange }: WidgetProps) {\n const fields = useFormDataFields();\n const [rows, setRows] = useState<ValidateRow[]>(() => validateToRows(value));\n const prevValueRef = useRef(value);\n // 自身 onChange 引发的 value 回传不应触发重建(否则每次输入都被重置)\n const lastEmittedRef = useRef(value);\n\n useEffect(() => {\n if (prevValueRef.current !== value) {\n prevValueRef.current = value;\n if (value !== lastEmittedRef.current) {\n setRows(validateToRows(value));\n }\n }\n }, [value]);\n\n const commit = (next: ValidateRow[]) => {\n setRows(next);\n const emitted = rowsToValidate(next);\n lastEmittedRef.current = emitted;\n onChange(emitted);\n };\n\n const updateRow = (id: string, patch: Partial<ValidateRow>) => {\n commit(rows.map((r) => (r.id === id ? { ...r, ...patch } : r)));\n };\n\n const removeRow = (id: string) => {\n commit(rows.filter((r) => r.id !== id));\n };\n\n const addRow = () => {\n commit([...rows, { id: genId(), key: '', expr: '{{ }}' }]);\n };\n\n return (\n <div style={{ width: '100%' }}>\n {rows.length === 0 ? (\n <div\n style={{\n fontSize: 11,\n color: '#999',\n background: '#fafafa',\n border: '1px dashed #e0e0e0',\n borderRadius: 6,\n padding: '6px 8px',\n marginBottom: 4,\n }}\n >\n 点击下方「添加校验规则」,组合 校验名称 + 表达式(变量 / 操作符 /\n 值)。表达式需返回 boolean,可用变量:$self.value、formData。\n </div>\n ) : (\n rows.map((row, i) => (\n <div\n key={row.id}\n style={{\n border: '1px solid #e8e8e8',\n borderRadius: 8,\n padding: 8,\n marginBottom: 8,\n background: '#fff',\n }}\n >\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n marginBottom: 6,\n }}\n >\n <span style={{ fontSize: 12, fontWeight: 600, color: '#333' }}>\n 校验规则 {i + 1}\n </span>\n <Button size='small' danger onClick={() => removeRow(row.id)}>\n 删除\n </Button>\n </div>\n <div style={{ marginBottom: 6 }}>\n <div style={{ fontSize: 11, color: '#666', marginBottom: 2 }}>\n 规则名称(key)\n </div>\n <Input\n size='small'\n placeholder='如 match / len'\n value={row.key}\n onChange={(e) => updateRow(row.id, { key: e.target.value })}\n />\n </div>\n <div>\n <div style={{ fontSize: 11, color: '#666', marginBottom: 2 }}>\n 校验表达式(需返回 boolean)\n </div>\n <ExpressionBuilder\n value={row.expr}\n onChange={(s) => updateRow(row.id, { expr: s })}\n fields={fields}\n showSelf\n placeholder='{{ $self.value.length >= 6 }}'\n />\n </div>\n </div>\n ))\n )}\n\n <Button size='small' type='dashed' block onClick={addRow}>\n + 添加校验规则\n </Button>\n <div style={{ fontSize: 11, color: '#999', marginTop: 4 }}>\n 提示:依赖字段(formData.xxx)变化时会自动联动重校验。\n </div>\n </div>\n );\n}\n\nexport const validateEditorWidget = ValidateEditor;\n"],"names":["validateToRows","value","key","expr","genId","rowsToValidate","rows","result","row","ValidateEditor","onChange","fields","useFormDataFields","setRows","useState","prevValueRef","useRef","lastEmittedRef","useEffect","commit","next","emitted","updateRow","id","patch","r","removeRow","addRow","jsx","jsxs","Button","Input","e","ExpressionBuilder","s","validateEditorWidget"],"mappings":";;;;;;AAoBA,SAASA,EAAeC,GAA+B;AACrD,SAAI,CAACA,KAAS,OAAOA,KAAU,WACtB,CAAA,IAEF,OAAO,QAAQA,CAAgC,EAAE;AAAA,IACtD,CAAC,CAACC,GAAKC,CAAI,OAAO,EAAE,IAAIC,KAAS,KAAAF,GAAK,MAAM,OAAOC,KAAQ,EAAE,EAAA;AAAA,EAAE;AAEnE;AAGA,SAASE,EACPC,GACoC;AACpC,QAAMC,IAAiC,CAAA;AACvC,aAAWC,KAAOF,GAAM;AACtB,UAAMJ,IAAMM,EAAI,IAAI,KAAA,GACdL,IAAOK,EAAI,KAAK,KAAA;AACtB,IAAI,CAACN,KAAO,CAACC,KAAQA,MAAS,aAG9BI,EAAOL,CAAG,IAAIC;AAAA,EAChB;AACA,SAAO,OAAO,KAAKI,CAAM,EAAE,SAAS,IAAIA,IAAS;AACnD;AAEO,SAASE,EAAe,EAAE,OAAAR,GAAO,UAAAS,KAAyB;AAC/D,QAAMC,IAASC,EAAA,GACT,CAACN,GAAMO,CAAO,IAAIC,EAAwB,MAAMd,EAAeC,CAAK,CAAC,GACrEc,IAAeC,EAAOf,CAAK,GAE3BgB,IAAiBD,EAAOf,CAAK;AAEnC,EAAAiB,EAAU,MAAM;AACd,IAAIH,EAAa,YAAYd,MAC3Bc,EAAa,UAAUd,GACnBA,MAAUgB,EAAe,WAC3BJ,EAAQb,EAAeC,CAAK,CAAC;AAAA,EAGnC,GAAG,CAACA,CAAK,CAAC;AAEV,QAAMkB,IAAS,CAACC,MAAwB;AACtC,IAAAP,EAAQO,CAAI;AACZ,UAAMC,IAAUhB,EAAee,CAAI;AACnC,IAAAH,EAAe,UAAUI,GACzBX,EAASW,CAAO;AAAA,EAClB,GAEMC,IAAY,CAACC,GAAYC,MAAgC;AAC7D,IAAAL,EAAOb,EAAK,IAAI,CAACmB,MAAOA,EAAE,OAAOF,IAAK,EAAE,GAAGE,GAAG,GAAGD,EAAA,IAAUC,CAAE,CAAC;AAAA,EAChE,GAEMC,IAAY,CAACH,MAAe;AAChC,IAAAJ,EAAOb,EAAK,OAAO,CAACmB,MAAMA,EAAE,OAAOF,CAAE,CAAC;AAAA,EACxC,GAEMI,IAAS,MAAM;AACnB,IAAAR,EAAO,CAAC,GAAGb,GAAM,EAAE,IAAIF,KAAS,KAAK,IAAI,MAAM,SAAA,CAAU,CAAC;AAAA,EAC5D;AAEA,2BACG,OAAA,EAAI,OAAO,EAAE,OAAO,UAClB,UAAA;AAAA,IAAAE,EAAK,WAAW,IACf,gBAAAsB;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,OAAO;AAAA,UACL,UAAU;AAAA,UACV,OAAO;AAAA,UACP,YAAY;AAAA,UACZ,QAAQ;AAAA,UACR,cAAc;AAAA,UACd,SAAS;AAAA,UACT,cAAc;AAAA,QAAA;AAAA,QAEjB,UAAA;AAAA,MAAA;AAAA,IAAA,IAKDtB,EAAK,IAAI,CAACE,GAAK,MACb,gBAAAqB;AAAA,MAAC;AAAA,MAAA;AAAA,QAEC,OAAO;AAAA,UACL,QAAQ;AAAA,UACR,cAAc;AAAA,UACd,SAAS;AAAA,UACT,cAAc;AAAA,UACd,YAAY;AAAA,QAAA;AAAA,QAGd,UAAA;AAAA,UAAA,gBAAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAO;AAAA,gBACL,SAAS;AAAA,gBACT,YAAY;AAAA,gBACZ,gBAAgB;AAAA,gBAChB,cAAc;AAAA,cAAA;AAAA,cAGhB,UAAA;AAAA,gBAAA,gBAAAA,EAAC,QAAA,EAAK,OAAO,EAAE,UAAU,IAAI,YAAY,KAAK,OAAO,OAAA,GAAU,UAAA;AAAA,kBAAA;AAAA,kBACvD,IAAI;AAAA,gBAAA,GACZ;AAAA,gBACA,gBAAAD,EAACE,GAAA,EAAO,MAAK,SAAQ,QAAM,IAAC,SAAS,MAAMJ,EAAUlB,EAAI,EAAE,GAAG,UAAA,KAAA,CAE9D;AAAA,cAAA;AAAA,YAAA;AAAA,UAAA;AAAA,4BAED,OAAA,EAAI,OAAO,EAAE,cAAc,KAC1B,UAAA;AAAA,YAAA,gBAAAoB,EAAC,OAAA,EAAI,OAAO,EAAE,UAAU,IAAI,OAAO,QAAQ,cAAc,EAAA,GAAK,UAAA,YAAA,CAE9D;AAAA,YACA,gBAAAA;AAAA,cAACG;AAAA,cAAA;AAAA,gBACC,MAAK;AAAA,gBACL,aAAY;AAAA,gBACZ,OAAOvB,EAAI;AAAA,gBACX,UAAU,CAACwB,MAAMV,EAAUd,EAAI,IAAI,EAAE,KAAKwB,EAAE,OAAO,MAAA,CAAO;AAAA,cAAA;AAAA,YAAA;AAAA,UAC5D,GACF;AAAA,4BACC,OAAA,EACC,UAAA;AAAA,YAAA,gBAAAJ,EAAC,OAAA,EAAI,OAAO,EAAE,UAAU,IAAI,OAAO,QAAQ,cAAc,EAAA,GAAK,UAAA,qBAAA,CAE9D;AAAA,YACA,gBAAAA;AAAA,cAACK;AAAA,cAAA;AAAA,gBACC,OAAOzB,EAAI;AAAA,gBACX,UAAU,CAAC0B,MAAMZ,EAAUd,EAAI,IAAI,EAAE,MAAM0B,GAAG;AAAA,gBAC9C,QAAAvB;AAAA,gBACA,UAAQ;AAAA,gBACR,aAAY;AAAA,cAAA;AAAA,YAAA;AAAA,UACd,EAAA,CACF;AAAA,QAAA;AAAA,MAAA;AAAA,MA9CKH,EAAI;AAAA,IAAA,CAgDZ;AAAA,IAGH,gBAAAoB,EAACE,GAAA,EAAO,MAAK,SAAQ,MAAK,UAAS,OAAK,IAAC,SAASH,GAAQ,UAAA,WAAA,CAE1D;AAAA,IACA,gBAAAC,EAAC,OAAA,EAAI,OAAO,EAAE,UAAU,IAAI,OAAO,QAAQ,WAAW,KAAK,UAAA,oCAAA,CAE3D;AAAA,EAAA,GACF;AAEJ;AAEO,MAAMO,IAAuB1B;"}
|