best-lowcode-runtime 0.2.7 → 0.2.8
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/dev.js +38 -11
- package/dist/dev.js.map +2 -2
- package/dist/index.js +252 -70
- package/dist/index.js.map +3 -3
- package/dist/lowcode/BestCrudPage.d.ts.map +1 -1
- package/dist/lowcode/dev.d.ts.map +1 -1
- package/dist/lowcode/index.d.ts +1 -1
- package/dist/lowcode/index.d.ts.map +1 -1
- package/dist/lowcode/schema.d.ts +46 -2
- package/dist/lowcode/schema.d.ts.map +1 -1
- package/dist/lowcode/validate.d.ts.map +1 -1
- package/dist/ui/BestDetail.d.ts +30 -1
- package/dist/ui/BestDetail.d.ts.map +1 -1
- package/dist/ui/BestOverlay.d.ts +4 -2
- package/dist/ui/BestOverlay.d.ts.map +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/types.d.ts +7 -0
- package/dist/ui/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -34,7 +34,7 @@ function createBestCrudAdapter(options = {}) {
|
|
|
34
34
|
|
|
35
35
|
// src/lowcode/BestCrudPage.tsx
|
|
36
36
|
import { Button as Button4, Modal as Modal2, message } from "antd";
|
|
37
|
-
import
|
|
37
|
+
import dayjs6 from "dayjs";
|
|
38
38
|
import { useCallback as useCallback2, useEffect as useEffect3, useLayoutEffect, useMemo as useMemo5, useRef as useRef3, useState as useState4 } from "react";
|
|
39
39
|
|
|
40
40
|
// src/runtime/BestProvider.tsx
|
|
@@ -169,15 +169,66 @@ function BestBatchInput({
|
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
// src/ui/BestDetail.tsx
|
|
172
|
-
import { Descriptions } from "antd";
|
|
173
|
-
import
|
|
174
|
-
|
|
175
|
-
|
|
172
|
+
import { Descriptions, Empty, Table, Typography } from "antd";
|
|
173
|
+
import dayjs2 from "dayjs";
|
|
174
|
+
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
175
|
+
function BestDetail({ fields, record = {}, column = 2, sections, sectionColumns, sectionGap = 20 }) {
|
|
176
|
+
const content = sections?.length ? /* @__PURE__ */ jsx3("div", { style: { display: "grid", gridTemplateColumns: `repeat(${sectionColumns ?? 1}, minmax(0, 1fr))`, gap: sectionGap }, children: sections.map((section) => {
|
|
177
|
+
const card = section.variant === "card";
|
|
178
|
+
return /* @__PURE__ */ jsxs("section", { style: { gridColumn: section.span ? `span ${section.span}` : void 0, marginBottom: 0, border: card ? "1px solid #f0f0f0" : void 0, borderRadius: card ? 6 : void 0, overflow: card ? "hidden" : void 0, background: card ? "#fff" : void 0 }, children: [
|
|
179
|
+
section.title ? /* @__PURE__ */ jsx3("div", { style: { padding: card ? "8px 12px" : void 0, background: card ? "#fafafa" : void 0, borderBottom: card ? "1px solid #f0f0f0" : void 0 }, children: /* @__PURE__ */ jsx3(Typography.Title, { level: 5, style: { margin: 0 }, children: section.title }) }) : null,
|
|
180
|
+
/* @__PURE__ */ jsxs("div", { style: { padding: card ? 12 : void 0 }, children: [
|
|
181
|
+
section.description ? /* @__PURE__ */ jsx3(Typography.Paragraph, { type: "secondary", children: section.description }) : null,
|
|
182
|
+
section.content,
|
|
183
|
+
section.fields ? /* @__PURE__ */ jsx3(FieldDescriptions, { fields: section.fields, record, column: section.columns ?? column }) : null,
|
|
184
|
+
section.table ? /* @__PURE__ */ jsx3(DetailTable, { table: section.table }) : null
|
|
185
|
+
] })
|
|
186
|
+
] }, section.key);
|
|
187
|
+
}) }) : /* @__PURE__ */ jsx3(FieldDescriptions, { fields, record, column });
|
|
188
|
+
return content;
|
|
189
|
+
}
|
|
190
|
+
function FieldDescriptions({ fields, record, column }) {
|
|
191
|
+
const visibleFields = fields.filter((field) => field.visible !== false);
|
|
192
|
+
return /* @__PURE__ */ jsx3(Descriptions, { bordered: true, column, size: "small", children: visibleFields.map((field) => {
|
|
176
193
|
const value = getPathValue(record, field.field);
|
|
177
|
-
const display = field.render ? field.render(value, record) : field.valueEnum?.[String(value)] ?? (value
|
|
194
|
+
const display = field.render ? field.render(value, record) : field.valueEnum?.[String(value)] ?? formatValue(value, field.format, field.emptyText);
|
|
178
195
|
return /* @__PURE__ */ jsx3(Descriptions.Item, { label: field.label, span: field.span, children: display }, field.field);
|
|
179
196
|
}) });
|
|
180
197
|
}
|
|
198
|
+
function DetailTable({ table }) {
|
|
199
|
+
if (!table.data.length) return /* @__PURE__ */ jsx3(Empty, { image: Empty.PRESENTED_IMAGE_SIMPLE, description: "\u6682\u65E0\u6570\u636E" });
|
|
200
|
+
return /* @__PURE__ */ jsx3(
|
|
201
|
+
Table,
|
|
202
|
+
{
|
|
203
|
+
size: "small",
|
|
204
|
+
bordered: true,
|
|
205
|
+
pagination: false,
|
|
206
|
+
rowKey: table.rowKey,
|
|
207
|
+
dataSource: table.data,
|
|
208
|
+
scroll: table.scrollX ? { x: table.scrollX } : void 0,
|
|
209
|
+
columns: table.columns.map((column) => ({ ...column, dataIndex: column.dataIndex ?? column.key }))
|
|
210
|
+
}
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
function formatValue(value, format, emptyText = "-") {
|
|
214
|
+
if (value == null || value === "") return emptyText;
|
|
215
|
+
const type = typeof format === "object" ? format.type : format;
|
|
216
|
+
if (!type || type === "text") return String(value);
|
|
217
|
+
if (type === "number") {
|
|
218
|
+
const number = Number(value);
|
|
219
|
+
if (!Number.isFinite(number)) return String(value);
|
|
220
|
+
const precision = typeof format === "object" ? format.precision : void 0;
|
|
221
|
+
return number.toLocaleString("zh-CN", precision === void 0 ? void 0 : { minimumFractionDigits: precision, maximumFractionDigits: precision });
|
|
222
|
+
}
|
|
223
|
+
if (type === "money") {
|
|
224
|
+
const number = Number(value);
|
|
225
|
+
return Number.isFinite(number) ? number.toLocaleString("zh-CN", { minimumFractionDigits: 2, maximumFractionDigits: 2 }) : String(value);
|
|
226
|
+
}
|
|
227
|
+
if (type === "boolean") return value ? "\u662F" : "\u5426";
|
|
228
|
+
if (type === "json") return typeof value === "string" ? value : JSON.stringify(value);
|
|
229
|
+
const date = dayjs2(value);
|
|
230
|
+
return date.isValid() ? date.format(type === "date" ? "YYYY-MM-DD" : "YYYY-MM-DD HH:mm:ss") : String(value);
|
|
231
|
+
}
|
|
181
232
|
function getPathValue(values, path) {
|
|
182
233
|
if (Object.hasOwn(values, path)) return values[path];
|
|
183
234
|
return path.split(".").reduce((current, part) => {
|
|
@@ -189,8 +240,8 @@ function getPathValue(values, path) {
|
|
|
189
240
|
}
|
|
190
241
|
|
|
191
242
|
// src/ui/BestFilePreview.tsx
|
|
192
|
-
import { Button, Image, List, Typography } from "antd";
|
|
193
|
-
import { jsx as jsx4, jsxs } from "react/jsx-runtime";
|
|
243
|
+
import { Button, Image, List, Typography as Typography2 } from "antd";
|
|
244
|
+
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
194
245
|
function isImage(file) {
|
|
195
246
|
return file.mimeType?.startsWith("image/") || /\.(avif|bmp|gif|jpe?g|png|svg|webp)(?:$|[?#])/i.test(file.url);
|
|
196
247
|
}
|
|
@@ -199,7 +250,7 @@ function BestFilePreview({ files, onDownload }) {
|
|
|
199
250
|
List,
|
|
200
251
|
{
|
|
201
252
|
dataSource: files,
|
|
202
|
-
renderItem: (file) => /* @__PURE__ */
|
|
253
|
+
renderItem: (file) => /* @__PURE__ */ jsxs2(
|
|
203
254
|
List.Item,
|
|
204
255
|
{
|
|
205
256
|
actions: [
|
|
@@ -207,7 +258,7 @@ function BestFilePreview({ files, onDownload }) {
|
|
|
207
258
|
],
|
|
208
259
|
children: [
|
|
209
260
|
isImage(file) ? /* @__PURE__ */ jsx4(Image, { alt: file.name ?? "\u6587\u4EF6\u9884\u89C8", height: 48, preview: true, src: file.url, width: 48 }) : null,
|
|
210
|
-
/* @__PURE__ */ jsx4(
|
|
261
|
+
/* @__PURE__ */ jsx4(Typography2.Text, { ellipsis: true, style: { marginInlineStart: isImage(file) ? 12 : 0 }, children: file.name ?? file.url })
|
|
211
262
|
]
|
|
212
263
|
}
|
|
213
264
|
)
|
|
@@ -217,9 +268,9 @@ function BestFilePreview({ files, onDownload }) {
|
|
|
217
268
|
|
|
218
269
|
// src/ui/BestForm.tsx
|
|
219
270
|
import { Button as Button2, DatePicker, Form, Input as Input2, InputNumber, Select, Space } from "antd";
|
|
220
|
-
import
|
|
271
|
+
import dayjs3 from "dayjs";
|
|
221
272
|
import { useEffect, useMemo as useMemo3, useRef, useState as useState3 } from "react";
|
|
222
|
-
import { Fragment, jsx as jsx5, jsxs as
|
|
273
|
+
import { Fragment, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
223
274
|
function toNamePath(path) {
|
|
224
275
|
return path === void 0 ? [] : Array.isArray(path) ? path : [path];
|
|
225
276
|
}
|
|
@@ -230,7 +281,7 @@ function isRecord(value) {
|
|
|
230
281
|
if (!value || typeof value !== "object" || Array.isArray(value) || value instanceof Date) {
|
|
231
282
|
return false;
|
|
232
283
|
}
|
|
233
|
-
if (
|
|
284
|
+
if (dayjs3.isDayjs(value)) return false;
|
|
234
285
|
const prototype = Object.getPrototypeOf(value);
|
|
235
286
|
return prototype === Object.prototype || prototype === null;
|
|
236
287
|
}
|
|
@@ -252,17 +303,17 @@ function resolveFieldDisabled(field, values, mode) {
|
|
|
252
303
|
return field.disabled || Boolean(field.disabledWhen && evaluateCondition(field.disabledWhen, values, mode));
|
|
253
304
|
}
|
|
254
305
|
function toDayjsValue(value) {
|
|
255
|
-
if (
|
|
256
|
-
if (value instanceof Date) return
|
|
306
|
+
if (dayjs3.isDayjs(value)) return value;
|
|
307
|
+
if (value instanceof Date) return dayjs3(value);
|
|
257
308
|
if (typeof value === "number") {
|
|
258
309
|
const normalized = Math.abs(value) >= 1e12 ? value : value * 1e3;
|
|
259
|
-
const parsed =
|
|
310
|
+
const parsed = dayjs3(normalized);
|
|
260
311
|
return parsed.isValid() ? parsed : null;
|
|
261
312
|
}
|
|
262
313
|
if (typeof value === "string") {
|
|
263
314
|
const trimmed = value.trim();
|
|
264
315
|
if (!trimmed) return null;
|
|
265
|
-
const parsed =
|
|
316
|
+
const parsed = dayjs3(trimmed);
|
|
266
317
|
return parsed.isValid() ? parsed : null;
|
|
267
318
|
}
|
|
268
319
|
return null;
|
|
@@ -356,7 +407,7 @@ function FormControl({
|
|
|
356
407
|
value: toDatePickerValue(value),
|
|
357
408
|
onChange: (date, dateString) => onChange?.(serializeDatePickerValue(date, dateString)),
|
|
358
409
|
disabled: field.disabled,
|
|
359
|
-
disabledDate: (current) => field.maxDate === "today" && current.isAfter(
|
|
410
|
+
disabledDate: (current) => field.maxDate === "today" && current.isAfter(dayjs3(), "day"),
|
|
360
411
|
style: { width: "100%" }
|
|
361
412
|
}
|
|
362
413
|
);
|
|
@@ -368,7 +419,7 @@ function FormControl({
|
|
|
368
419
|
value: toDateRangePickerValue(value),
|
|
369
420
|
onChange: (dates, dateStrings) => onChange?.(serializeDateRangePickerValue(dates, dateStrings)),
|
|
370
421
|
disabled: field.disabled,
|
|
371
|
-
disabledDate: (current) => field.maxDate === "today" && current.isAfter(
|
|
422
|
+
disabledDate: (current) => field.maxDate === "today" && current.isAfter(dayjs3(), "day"),
|
|
372
423
|
style: { width: "100%" }
|
|
373
424
|
}
|
|
374
425
|
);
|
|
@@ -427,7 +478,7 @@ function RepeatableField({
|
|
|
427
478
|
values
|
|
428
479
|
}) {
|
|
429
480
|
const listName = namePath ?? field.field;
|
|
430
|
-
return /* @__PURE__ */ jsx5(Form.List, { name: listName, children: (items, { add, remove }) => /* @__PURE__ */
|
|
481
|
+
return /* @__PURE__ */ jsx5(Form.List, { name: listName, children: (items, { add, remove }) => /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
431
482
|
items.map((item) => /* @__PURE__ */ jsx5(
|
|
432
483
|
RepeatableFieldRow,
|
|
433
484
|
{
|
|
@@ -477,7 +528,7 @@ function RepeatableFieldRow({
|
|
|
477
528
|
}
|
|
478
529
|
});
|
|
479
530
|
}, [field.itemFields, form, itemPath, mode, scopeValues, values]);
|
|
480
|
-
return /* @__PURE__ */
|
|
531
|
+
return /* @__PURE__ */ jsxs3(Space, { align: "start", children: [
|
|
481
532
|
field.itemFields?.map((itemField) => {
|
|
482
533
|
if (!isFieldVisible(itemField, scopeValues, mode)) return null;
|
|
483
534
|
const nextPath = appendNamePath(itemPath, itemField.field);
|
|
@@ -743,9 +794,9 @@ function BestFormBody({
|
|
|
743
794
|
onCancel
|
|
744
795
|
}) {
|
|
745
796
|
const [form] = Form.useForm();
|
|
746
|
-
return /* @__PURE__ */
|
|
797
|
+
return /* @__PURE__ */ jsxs3(Form, { form, initialValues, layout: "vertical", onFinish: onSubmit, children: [
|
|
747
798
|
/* @__PURE__ */ jsx5(FormFields, { fields, form, initialValues, mode }),
|
|
748
|
-
/* @__PURE__ */
|
|
799
|
+
/* @__PURE__ */ jsxs3(Space, { children: [
|
|
749
800
|
/* @__PURE__ */ jsx5(Button2, { htmlType: "submit", loading, type: "primary", children: submitText }),
|
|
750
801
|
onCancel ? /* @__PURE__ */ jsx5(Button2, { onClick: onCancel, children: "\u53D6\u6D88" }) : null,
|
|
751
802
|
extra
|
|
@@ -807,7 +858,7 @@ function evaluateCondition(condition, values, mode) {
|
|
|
807
858
|
}
|
|
808
859
|
|
|
809
860
|
// src/ui/BestLightTable.tsx
|
|
810
|
-
import { Table } from "antd";
|
|
861
|
+
import { Table as Table2 } from "antd";
|
|
811
862
|
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
812
863
|
function BestLightTable({
|
|
813
864
|
columns,
|
|
@@ -822,7 +873,7 @@ function BestLightTable({
|
|
|
822
873
|
render: column.render
|
|
823
874
|
}));
|
|
824
875
|
return /* @__PURE__ */ jsx6(
|
|
825
|
-
|
|
876
|
+
Table2,
|
|
826
877
|
{
|
|
827
878
|
columns: tableColumns,
|
|
828
879
|
dataSource: data,
|
|
@@ -836,18 +887,18 @@ function BestLightTable({
|
|
|
836
887
|
// src/ui/BestOverlay.tsx
|
|
837
888
|
import { Drawer, Modal } from "antd";
|
|
838
889
|
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
839
|
-
function BestDrawer({ children, open, title, onClose }) {
|
|
840
|
-
return /* @__PURE__ */ jsx7(Drawer, { destroyOnHidden: true, open, title, width: 640, onClose, children });
|
|
890
|
+
function BestDrawer({ children, open, title, onClose, width, footer }) {
|
|
891
|
+
return /* @__PURE__ */ jsx7(Drawer, { destroyOnHidden: true, open, title, width: width ?? 640, footer, onClose, children });
|
|
841
892
|
}
|
|
842
|
-
function BestModal({ children, open, title, onClose }) {
|
|
843
|
-
return /* @__PURE__ */ jsx7(Modal, { destroyOnHidden: true, footer: null, open, title, onCancel: onClose, children });
|
|
893
|
+
function BestModal({ children, open, title, onClose, width, footer }) {
|
|
894
|
+
return /* @__PURE__ */ jsx7(Modal, { destroyOnHidden: true, footer: footer ?? null, open, title, width, onCancel: onClose, children });
|
|
844
895
|
}
|
|
845
896
|
|
|
846
897
|
// src/ui/BestSearch.tsx
|
|
847
898
|
import { Button as Button3, Col, DatePicker as DatePicker2, Form as Form2, Input as Input3, InputNumber as InputNumber2, Row, Select as Select2 } from "antd";
|
|
848
|
-
import
|
|
899
|
+
import dayjs4 from "dayjs";
|
|
849
900
|
import { useEffect as useEffect2, useMemo as useMemo4, useRef as useRef2 } from "react";
|
|
850
|
-
import { jsx as jsx8, jsxs as
|
|
901
|
+
import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
851
902
|
function searchFormSignature(fields, initialValues) {
|
|
852
903
|
return JSON.stringify([
|
|
853
904
|
fields.map((field) => ({
|
|
@@ -912,7 +963,7 @@ function FieldControl({ field, value, onChange, ...controlProps }) {
|
|
|
912
963
|
value: toDatePickerValue(value),
|
|
913
964
|
onChange: (date, dateString) => onChange?.(serializeDatePickerValue(date, dateString)),
|
|
914
965
|
disabled: field.disabled,
|
|
915
|
-
disabledDate: (current) => field.maxDate === "today" && current.isAfter(
|
|
966
|
+
disabledDate: (current) => field.maxDate === "today" && current.isAfter(dayjs4(), "day"),
|
|
916
967
|
placeholder: field.placeholder,
|
|
917
968
|
style: { width: "100%" }
|
|
918
969
|
}
|
|
@@ -925,7 +976,7 @@ function FieldControl({ field, value, onChange, ...controlProps }) {
|
|
|
925
976
|
value: toDateRangePickerValue(value),
|
|
926
977
|
onChange: (dates, dateStrings) => onChange?.(serializeDateRangePickerValue(dates, dateStrings)),
|
|
927
978
|
disabled: field.disabled,
|
|
928
|
-
disabledDate: (current) => field.maxDate === "today" && current.isAfter(
|
|
979
|
+
disabledDate: (current) => field.maxDate === "today" && current.isAfter(dayjs4(), "day"),
|
|
929
980
|
style: { width: "100%" }
|
|
930
981
|
}
|
|
931
982
|
);
|
|
@@ -1027,9 +1078,9 @@ function BestSearchBody({
|
|
|
1027
1078
|
onFinish: (values) => onSearch(values),
|
|
1028
1079
|
onValuesChange: (_, values) => onChange?.(values),
|
|
1029
1080
|
className: "best-lowcode-search",
|
|
1030
|
-
children: /* @__PURE__ */
|
|
1081
|
+
children: /* @__PURE__ */ jsxs4(Row, { gutter: 16, align: "bottom", children: [
|
|
1031
1082
|
fields.filter((field) => !field.hidden).map((field) => /* @__PURE__ */ jsx8(Col, { span: field.span ?? 6, children: /* @__PURE__ */ jsx8(Form2.Item, { label: field.label, name: field.field, rules: toAntRules(field.rules), children: /* @__PURE__ */ jsx8(FieldControl, { field }) }) }, field.field)),
|
|
1032
|
-
/* @__PURE__ */ jsx8(Col, { children: /* @__PURE__ */
|
|
1083
|
+
/* @__PURE__ */ jsx8(Col, { children: /* @__PURE__ */ jsxs4(Form2.Item, { children: [
|
|
1033
1084
|
/* @__PURE__ */ jsx8(Button3, { htmlType: "submit", loading, type: "primary", children: submitText }),
|
|
1034
1085
|
/* @__PURE__ */ jsx8(
|
|
1035
1086
|
Button3,
|
|
@@ -1052,13 +1103,13 @@ function BestSearchBody({
|
|
|
1052
1103
|
}
|
|
1053
1104
|
|
|
1054
1105
|
// src/ui/BestStates.tsx
|
|
1055
|
-
import { Empty, Result, Spin } from "antd";
|
|
1106
|
+
import { Empty as Empty2, Result, Spin } from "antd";
|
|
1056
1107
|
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
1057
1108
|
function BestLoading({ description = "\u52A0\u8F7D\u4E2D" }) {
|
|
1058
1109
|
return /* @__PURE__ */ jsx9("div", { style: { display: "grid", minHeight: 160, placeItems: "center" }, children: /* @__PURE__ */ jsx9(Spin, { tip: description }) });
|
|
1059
1110
|
}
|
|
1060
1111
|
function BestEmpty({ description = "\u6682\u65E0\u6570\u636E" }) {
|
|
1061
|
-
return /* @__PURE__ */ jsx9(
|
|
1112
|
+
return /* @__PURE__ */ jsx9(Empty2, { description });
|
|
1062
1113
|
}
|
|
1063
1114
|
function BestError({ description = "\u52A0\u8F7D\u5931\u8D25" }) {
|
|
1064
1115
|
return /* @__PURE__ */ jsx9(Result, { status: "error", title: description });
|
|
@@ -1109,9 +1160,9 @@ function BestTable({
|
|
|
1109
1160
|
}
|
|
1110
1161
|
|
|
1111
1162
|
// src/lowcode/runtime.ts
|
|
1112
|
-
import
|
|
1163
|
+
import dayjs5 from "dayjs";
|
|
1113
1164
|
import utc from "dayjs/plugin/utc.js";
|
|
1114
|
-
|
|
1165
|
+
dayjs5.extend(utc);
|
|
1115
1166
|
function toBestListQuery(params, sort) {
|
|
1116
1167
|
const { current, pageSize, ...filters } = params;
|
|
1117
1168
|
const normalizedSort = Object.fromEntries(
|
|
@@ -1144,7 +1195,7 @@ function formatCrudValue(value, format) {
|
|
|
1144
1195
|
const numericValue = typeof value === "number" ? value : Number(value.trim());
|
|
1145
1196
|
timestamp = Number.isFinite(numericValue) && numericValue !== 0 ? Math.abs(numericValue) >= 1e12 ? numericValue : numericValue * 1e3 : value;
|
|
1146
1197
|
}
|
|
1147
|
-
const date =
|
|
1198
|
+
const date = dayjs5.utc(timestamp);
|
|
1148
1199
|
if (!date.isValid()) return String(value);
|
|
1149
1200
|
return date.format(format === "date" ? "YYYY-MM-DD" : "YYYY-MM-DD HH:mm:ss");
|
|
1150
1201
|
}
|
|
@@ -1219,9 +1270,11 @@ var builtInEffects = /* @__PURE__ */ new Set([
|
|
|
1219
1270
|
"openEdit",
|
|
1220
1271
|
"remove",
|
|
1221
1272
|
"runAction",
|
|
1222
|
-
"slot"
|
|
1273
|
+
"slot",
|
|
1274
|
+
"closeDetail"
|
|
1223
1275
|
]);
|
|
1224
1276
|
var columnFormats = /* @__PURE__ */ new Set(["date", "datetime", "money", "text"]);
|
|
1277
|
+
var detailFormats = /* @__PURE__ */ new Set(["text", "number", "money", "date", "datetime", "boolean", "json"]);
|
|
1225
1278
|
function push(diagnostics, path, code, message2) {
|
|
1226
1279
|
diagnostics.push({ path, code, message: message2 });
|
|
1227
1280
|
}
|
|
@@ -1268,6 +1321,14 @@ function validateCondition(condition, path, diagnostics) {
|
|
|
1268
1321
|
}
|
|
1269
1322
|
push(diagnostics, path, "condition.operator", `\u4E0D\u652F\u6301\u7684\u6761\u4EF6\uFF1A${condition.operator}`);
|
|
1270
1323
|
}
|
|
1324
|
+
function validateDetailField(field, path, registry, diagnostics) {
|
|
1325
|
+
if (field.visibleWhen) validateCondition(field.visibleWhen, `${path}/visibleWhen`, diagnostics);
|
|
1326
|
+
if (field.slot && registry && !registry.slots[field.slot])
|
|
1327
|
+
push(diagnostics, `${path}/slot`, "registry.slot", `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${field.slot}`);
|
|
1328
|
+
const format = typeof field.format === "object" ? field.format.type : field.format;
|
|
1329
|
+
if (format && !detailFormats.has(format))
|
|
1330
|
+
push(diagnostics, `${path}/format`, "detail.format", `\u4E0D\u652F\u6301\u7684\u8BE6\u60C5\u683C\u5F0F\uFF1A${format}`);
|
|
1331
|
+
}
|
|
1271
1332
|
function validateFields(fields, path, registry, diagnostics) {
|
|
1272
1333
|
const seen = /* @__PURE__ */ new Set();
|
|
1273
1334
|
fields?.forEach((field, index) => {
|
|
@@ -1421,17 +1482,26 @@ function validateCrudPageSchema(schema, registry) {
|
|
|
1421
1482
|
}
|
|
1422
1483
|
});
|
|
1423
1484
|
if (schema.detail !== void 0) {
|
|
1424
|
-
if (!schema.detail || typeof schema.detail !== "object" || !Array.isArray(schema.detail.fields)) {
|
|
1425
|
-
push(diagnostics, "/detail", "detail.type", "detail \u5FC5\u987B\u5305\u542B fields \
|
|
1485
|
+
if (!schema.detail || typeof schema.detail !== "object" || schema.detail.fields !== void 0 && !Array.isArray(schema.detail.fields) || schema.detail.sections !== void 0 && !Array.isArray(schema.detail.sections)) {
|
|
1486
|
+
push(diagnostics, "/detail", "detail.type", "detail \u5FC5\u987B\u5305\u542B fields \u6216 sections \u6570\u7EC4");
|
|
1426
1487
|
} else {
|
|
1427
|
-
schema.detail.fields
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
);
|
|
1488
|
+
schema.detail.fields?.forEach((field, index) => validateDetailField(field, `/detail/fields/${index}`, registry, diagnostics));
|
|
1489
|
+
schema.detail.sections?.forEach((section, index) => {
|
|
1490
|
+
if (section.visibleWhen) validateCondition(section.visibleWhen, `/detail/sections/${index}/visibleWhen`, diagnostics);
|
|
1491
|
+
if (!section.key) push(diagnostics, `/detail/sections/${index}/key`, "detail.section.key", "\u8BE6\u60C5\u533A\u5757\u5FC5\u987B\u6307\u5B9A key");
|
|
1492
|
+
if (section.span !== void 0 && (!Number.isInteger(section.span) || section.span < 1))
|
|
1493
|
+
push(diagnostics, `/detail/sections/${index}/span`, "detail.section.span", "\u8BE6\u60C5\u533A\u5757 span \u5FC5\u987B\u662F\u6B63\u6574\u6570");
|
|
1494
|
+
if (section.columns !== void 0 && (!Number.isInteger(section.columns) || section.columns < 1))
|
|
1495
|
+
push(diagnostics, `/detail/sections/${index}/columns`, "detail.section.columns", "\u8BE6\u60C5\u5B57\u6BB5 columns \u5FC5\u987B\u662F\u6B63\u6574\u6570");
|
|
1496
|
+
if (section.layout === "slot" && !section.slot)
|
|
1497
|
+
push(diagnostics, `/detail/sections/${index}/slot`, "detail.slot", "slot \u533A\u5757\u5FC5\u987B\u6307\u5B9A slot");
|
|
1498
|
+
if (section.layout === "table" && !section.table)
|
|
1499
|
+
push(diagnostics, `/detail/sections/${index}/table`, "detail.table", "table \u533A\u5757\u5FC5\u987B\u6307\u5B9A table");
|
|
1500
|
+
if (section.table && typeof section.table.data !== "string")
|
|
1501
|
+
push(diagnostics, `/detail/sections/${index}/table/data`, "detail.table.data", "\u8BE6\u60C5\u8868\u683C data \u5FC5\u987B\u662F\u5B57\u6BB5\u8DEF\u5F84");
|
|
1502
|
+
if (section.slot && registry && !registry.slots[section.slot])
|
|
1503
|
+
push(diagnostics, `/detail/sections/${index}/slot`, "registry.slot", `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${section.slot}`);
|
|
1504
|
+
section.fields?.forEach((field, fieldIndex) => validateDetailField(field, `/detail/sections/${index}/fields/${fieldIndex}`, registry, diagnostics));
|
|
1435
1505
|
});
|
|
1436
1506
|
}
|
|
1437
1507
|
}
|
|
@@ -1449,6 +1519,13 @@ function validateCrudPageSchema(schema, registry) {
|
|
|
1449
1519
|
Boolean(schema.dataSource?.remove),
|
|
1450
1520
|
diagnostics
|
|
1451
1521
|
);
|
|
1522
|
+
validateActions(
|
|
1523
|
+
schema.detail?.footer,
|
|
1524
|
+
"/detail/footer",
|
|
1525
|
+
registry,
|
|
1526
|
+
Boolean(schema.dataSource?.remove),
|
|
1527
|
+
diagnostics
|
|
1528
|
+
);
|
|
1452
1529
|
return { valid: diagnostics.length === 0, diagnostics };
|
|
1453
1530
|
}
|
|
1454
1531
|
function assertValidCrudPageSchema(schema, registry) {
|
|
@@ -1500,7 +1577,7 @@ ${message2}`);
|
|
|
1500
1577
|
}
|
|
1501
1578
|
|
|
1502
1579
|
// src/lowcode/BestCrudPage.tsx
|
|
1503
|
-
import { Fragment as Fragment2, jsx as jsx11, jsxs as
|
|
1580
|
+
import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1504
1581
|
function pickRowKeyValues(record, rowKey) {
|
|
1505
1582
|
if (!record) return {};
|
|
1506
1583
|
const keys = Array.isArray(rowKey) ? rowKey : [rowKey];
|
|
@@ -1573,7 +1650,7 @@ function useFields(fields = []) {
|
|
|
1573
1650
|
const registry = useBestRegistry();
|
|
1574
1651
|
return fields.map((field) => toFieldDefinition(field, registry.dictionaries, registry.slots));
|
|
1575
1652
|
}
|
|
1576
|
-
function toDetailField(field, dictionary, slots) {
|
|
1653
|
+
function toDetailField(field, dictionary, slots, record = {}) {
|
|
1577
1654
|
const slot = field.slot;
|
|
1578
1655
|
const valueEnum = field.dict ? Object.fromEntries(
|
|
1579
1656
|
(dictionary[field.dict] ?? []).map((item) => [String(item.value), item.label])
|
|
@@ -1582,10 +1659,50 @@ function toDetailField(field, dictionary, slots) {
|
|
|
1582
1659
|
field: field.field,
|
|
1583
1660
|
label: field.label,
|
|
1584
1661
|
span: field.span,
|
|
1662
|
+
format: field.format,
|
|
1663
|
+
emptyText: field.emptyText,
|
|
1664
|
+
visible: !field.visibleWhen || evaluateCondition(field.visibleWhen, record, "detail"),
|
|
1585
1665
|
valueEnum,
|
|
1586
|
-
render: slot ? (value,
|
|
1666
|
+
render: slot ? (value, record2) => slots[slot]?.({ field: field.field, record: record2, value }) ?? "-" : void 0
|
|
1587
1667
|
};
|
|
1588
1668
|
}
|
|
1669
|
+
function getPathValue3(values, path) {
|
|
1670
|
+
if (Object.hasOwn(values, path)) return values[path];
|
|
1671
|
+
return path.split(".").reduce((current, part) => {
|
|
1672
|
+
if (current && typeof current === "object") return current[part];
|
|
1673
|
+
return void 0;
|
|
1674
|
+
}, values);
|
|
1675
|
+
}
|
|
1676
|
+
function toDetailSection(section, record, dictionaries, slots) {
|
|
1677
|
+
if (section.visibleWhen && !evaluateCondition(section.visibleWhen, record, "detail")) return null;
|
|
1678
|
+
const fields = section.fields?.map((field) => toDetailField(field, dictionaries, slots, record));
|
|
1679
|
+
const table = section.table ? {
|
|
1680
|
+
key: section.key,
|
|
1681
|
+
data: getPathValue3(record, section.table.data) ?? [],
|
|
1682
|
+
rowKey: section.table.rowKey,
|
|
1683
|
+
scrollX: section.table.scrollX,
|
|
1684
|
+
columns: section.table.columns.map((column) => ({
|
|
1685
|
+
key: column.field,
|
|
1686
|
+
title: column.title,
|
|
1687
|
+
dataIndex: column.field,
|
|
1688
|
+
width: column.width,
|
|
1689
|
+
fixed: column.fixed,
|
|
1690
|
+
render: (value, row) => {
|
|
1691
|
+
if (column.slot) return slots[column.slot]?.({ field: column.field, record: row, value }) ?? "-";
|
|
1692
|
+
if (column.dict) {
|
|
1693
|
+
const item = (dictionaries[column.dict] ?? []).find((candidate) => candidate.value === value);
|
|
1694
|
+
if (item) return item.label;
|
|
1695
|
+
}
|
|
1696
|
+
const format = column.format;
|
|
1697
|
+
if (format === "date" || format === "datetime") return formatCrudValue(value, format);
|
|
1698
|
+
if (format === "money") return formatCrudValue(value, format);
|
|
1699
|
+
return value == null || value === "" ? "-" : String(value);
|
|
1700
|
+
}
|
|
1701
|
+
}))
|
|
1702
|
+
} : void 0;
|
|
1703
|
+
const content = section.layout === "slot" && section.slot ? slots[section.slot]?.({ record }) : void 0;
|
|
1704
|
+
return { key: section.key, title: section.title, description: section.description, columns: section.columns, span: section.span, variant: section.variant, fields, table, content };
|
|
1705
|
+
}
|
|
1589
1706
|
function toTableColumn(column, dictionary, slots) {
|
|
1590
1707
|
const slot = column.slot;
|
|
1591
1708
|
const valueEnum = column.dict ? Object.fromEntries(
|
|
@@ -1631,7 +1748,7 @@ function toProTableSearchColumn(field, dictionary) {
|
|
|
1631
1748
|
initialValue: field.defaultValue,
|
|
1632
1749
|
fieldProps: {
|
|
1633
1750
|
...options ? { options } : {},
|
|
1634
|
-
...field.maxDate === "today" ? { disabledDate: (current) => current.isAfter(
|
|
1751
|
+
...field.maxDate === "today" ? { disabledDate: (current) => current.isAfter(dayjs6(), "day") } : {}
|
|
1635
1752
|
}
|
|
1636
1753
|
};
|
|
1637
1754
|
}
|
|
@@ -1685,14 +1802,44 @@ function BestCrudPage({ adapter, className, schema }) {
|
|
|
1685
1802
|
userTouched: false
|
|
1686
1803
|
});
|
|
1687
1804
|
const [drawer, setDrawer] = useState4({ mode: "closed" });
|
|
1805
|
+
const [detailState, setDetailState] = useState4({ loading: false });
|
|
1806
|
+
const detailRequestRef = useRef3(void 0);
|
|
1688
1807
|
const [submitting, setSubmitting] = useState4(false);
|
|
1689
1808
|
const submittingRef = useRef3(false);
|
|
1690
1809
|
const handleAction = useCallback2(
|
|
1691
1810
|
async (action, record) => {
|
|
1692
1811
|
if (action.access && !registry.access(action.access)) return;
|
|
1812
|
+
if (action.effect === "closeDetail") {
|
|
1813
|
+
detailRequestRef.current?.abort();
|
|
1814
|
+
setDrawer({ mode: "closed" });
|
|
1815
|
+
setDetailState({ loading: false });
|
|
1816
|
+
return;
|
|
1817
|
+
}
|
|
1693
1818
|
if (action.effect !== "remove" && !await confirmBeforeAction(action.confirm, confirmAction))
|
|
1694
1819
|
return;
|
|
1695
|
-
if (action.effect === "openDetail")
|
|
1820
|
+
if (action.effect === "openDetail") {
|
|
1821
|
+
detailRequestRef.current?.abort();
|
|
1822
|
+
const controller = new AbortController();
|
|
1823
|
+
detailRequestRef.current = controller;
|
|
1824
|
+
setDrawer({ mode: "detail", record });
|
|
1825
|
+
setDetailState({ loading: Boolean(schema.dataSource.detail), record });
|
|
1826
|
+
if (schema.dataSource.detail) {
|
|
1827
|
+
const detailService = registry.services[schema.dataSource.detail];
|
|
1828
|
+
if (!detailService) {
|
|
1829
|
+
setDetailState({ loading: false, error: new Error(`\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.detail}`), record });
|
|
1830
|
+
return;
|
|
1831
|
+
}
|
|
1832
|
+
try {
|
|
1833
|
+
const detail = await detailService(record ?? {}, { signal: controller.signal });
|
|
1834
|
+
if (controller.signal.aborted) return;
|
|
1835
|
+
const normalized = isRecord2(detail) ? adapter?.fromDetail ? adapter.fromDetail(detail) : detail : record ?? {};
|
|
1836
|
+
setDetailState({ loading: false, record: normalized });
|
|
1837
|
+
setDrawer({ mode: "detail", record: normalized });
|
|
1838
|
+
} catch (error) {
|
|
1839
|
+
if (!controller.signal.aborted) setDetailState({ loading: false, error, record });
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1696
1843
|
if (action.effect === "openEdit") {
|
|
1697
1844
|
let editRecord = record;
|
|
1698
1845
|
if (schema.dataSource.detail) {
|
|
@@ -1858,7 +2005,7 @@ function BestCrudPage({ adapter, className, schema }) {
|
|
|
1858
2005
|
schema.dataSource.update
|
|
1859
2006
|
]
|
|
1860
2007
|
);
|
|
1861
|
-
return /* @__PURE__ */
|
|
2008
|
+
return /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
1862
2009
|
useBestSearch && searchFields.length ? /* @__PURE__ */ jsx11(
|
|
1863
2010
|
BestSearch,
|
|
1864
2011
|
{
|
|
@@ -1893,22 +2040,41 @@ function BestCrudPage({ adapter, className, schema }) {
|
|
|
1893
2040
|
toolBarRender: () => schema.toolbar?.map((action) => /* @__PURE__ */ jsx11(ActionButton, { action, onExecute: handleAction }, action.id)) ?? []
|
|
1894
2041
|
}
|
|
1895
2042
|
),
|
|
1896
|
-
/* @__PURE__ */
|
|
2043
|
+
drawer.mode === "detail" && schema.detail?.mode === "inline" ? /* @__PURE__ */ jsx11(DetailContent, { state: detailState, record: drawer.record }) : null,
|
|
2044
|
+
drawer.mode !== "closed" && (schema.detail?.mode !== "inline" || drawer.mode !== "detail") && schema.detail?.mode === "drawer" ? /* @__PURE__ */ jsxs5(
|
|
2045
|
+
BestDrawer,
|
|
2046
|
+
{
|
|
2047
|
+
open: true,
|
|
2048
|
+
width: schema.detail.width,
|
|
2049
|
+
title: drawer.mode === "detail" ? `${schema.title}\u8BE6\u60C5` : drawer.mode === "edit" ? `\u7F16\u8F91${schema.title}` : `\u65B0\u5EFA${schema.title}`,
|
|
2050
|
+
footer: drawer.mode === "detail" && schema.detail.footer?.length ? /* @__PURE__ */ jsx11("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8 }, children: schema.detail.footer.map((action) => /* @__PURE__ */ jsx11(ActionButton, { action, record: drawer.record, onExecute: handleAction }, action.id)) }) : void 0,
|
|
2051
|
+
onClose: () => {
|
|
2052
|
+
detailRequestRef.current?.abort();
|
|
2053
|
+
setDrawer({ mode: "closed" });
|
|
2054
|
+
setDetailState({ loading: false });
|
|
2055
|
+
},
|
|
2056
|
+
children: [
|
|
2057
|
+
drawer.mode === "detail" ? /* @__PURE__ */ jsx11(DetailContent, { state: detailState, record: drawer.record }) : null,
|
|
2058
|
+
drawer.mode === "edit" || drawer.mode === "create" ? /* @__PURE__ */ jsx11(BestForm, { fields: formFields, initialValues: drawer.record, loading: submitting, mode: drawer.mode, onCancel: () => setDrawer({ mode: "closed" }), onSubmit: (values) => {
|
|
2059
|
+
void submitForm(values);
|
|
2060
|
+
} }) : null
|
|
2061
|
+
]
|
|
2062
|
+
}
|
|
2063
|
+
) : null,
|
|
2064
|
+
drawer.mode !== "closed" && (schema.detail?.mode !== "inline" || drawer.mode !== "detail") && schema.detail?.mode !== "drawer" ? /* @__PURE__ */ jsxs5(
|
|
1897
2065
|
BestModal,
|
|
1898
2066
|
{
|
|
1899
|
-
open:
|
|
2067
|
+
open: true,
|
|
1900
2068
|
title: drawer.mode === "detail" ? `${schema.title}\u8BE6\u60C5` : drawer.mode === "edit" ? `\u7F16\u8F91${schema.title}` : `\u65B0\u5EFA${schema.title}`,
|
|
1901
|
-
|
|
2069
|
+
width: schema.detail?.width,
|
|
2070
|
+
footer: drawer.mode === "detail" && schema.detail?.footer?.length ? /* @__PURE__ */ jsx11("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8 }, children: schema.detail.footer.map((action) => /* @__PURE__ */ jsx11(ActionButton, { action, record: drawer.record, onExecute: handleAction }, action.id)) }) : void 0,
|
|
2071
|
+
onClose: () => {
|
|
2072
|
+
detailRequestRef.current?.abort();
|
|
2073
|
+
setDrawer({ mode: "closed" });
|
|
2074
|
+
setDetailState({ loading: false });
|
|
2075
|
+
},
|
|
1902
2076
|
children: [
|
|
1903
|
-
drawer.mode === "detail" ? /* @__PURE__ */ jsx11(
|
|
1904
|
-
BestDetail,
|
|
1905
|
-
{
|
|
1906
|
-
fields: schema.detail?.fields.map(
|
|
1907
|
-
(field) => toDetailField(field, registry.dictionaries, registry.slots)
|
|
1908
|
-
) ?? [],
|
|
1909
|
-
record: drawer.record
|
|
1910
|
-
}
|
|
1911
|
-
) : null,
|
|
2077
|
+
drawer.mode === "detail" ? /* @__PURE__ */ jsx11(DetailContent, { state: detailState, record: drawer.record }) : null,
|
|
1912
2078
|
drawer.mode === "edit" || drawer.mode === "create" ? /* @__PURE__ */ jsx11(
|
|
1913
2079
|
BestForm,
|
|
1914
2080
|
{
|
|
@@ -1924,8 +2090,24 @@ function BestCrudPage({ adapter, className, schema }) {
|
|
|
1924
2090
|
) : null
|
|
1925
2091
|
]
|
|
1926
2092
|
}
|
|
1927
|
-
)
|
|
2093
|
+
) : null
|
|
1928
2094
|
] });
|
|
2095
|
+
function DetailContent({ state, record }) {
|
|
2096
|
+
if (state.loading) return /* @__PURE__ */ jsx11(BestLoading, {});
|
|
2097
|
+
if (state.error) return /* @__PURE__ */ jsx11(BestError, { description: errorMessage(state.error, `${schema.title}\u8BE6\u60C5\u52A0\u8F7D\u5931\u8D25`) });
|
|
2098
|
+
if (!record) return /* @__PURE__ */ jsx11(BestEmpty, {});
|
|
2099
|
+
const sections = schema.detail?.sections?.map((section) => toDetailSection(section, record, registry.dictionaries, registry.slots)).filter(Boolean);
|
|
2100
|
+
return /* @__PURE__ */ jsx11(
|
|
2101
|
+
BestDetail,
|
|
2102
|
+
{
|
|
2103
|
+
fields: schema.detail?.fields?.map((field) => toDetailField(field, registry.dictionaries, registry.slots, record)) ?? [],
|
|
2104
|
+
sections,
|
|
2105
|
+
sectionColumns: schema.detail?.columns,
|
|
2106
|
+
sectionGap: schema.detail?.gap,
|
|
2107
|
+
record
|
|
2108
|
+
}
|
|
2109
|
+
);
|
|
2110
|
+
}
|
|
1929
2111
|
function ActionButton({
|
|
1930
2112
|
action,
|
|
1931
2113
|
record,
|