best-lowcode-runtime 0.2.7 → 0.2.9
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 +268 -71
- 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,14 +169,65 @@ 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", minWidth: 0, maxWidth: "100%", width: "100%", boxSizing: "border-box", 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: { minWidth: 0, maxWidth: "100%", 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("div", { style: { minWidth: 0, maxWidth: "100%", width: "100%", overflowX: "auto" }, children: /* @__PURE__ */ jsx3(Descriptions, { bordered: true, column, size: "small", style: { minWidth: 0 }, 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
|
+
}) }) });
|
|
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("div", { style: { minWidth: 0, maxWidth: "100%", width: "100%", overflowX: "auto" }, children: /* @__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);
|
|
180
231
|
}
|
|
181
232
|
function getPathValue(values, path) {
|
|
182
233
|
if (Object.hasOwn(values, path)) return values[path];
|
|
@@ -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,33 @@ 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(
|
|
893
|
+
function BestModal({ children, open, title, onClose, width, footer }) {
|
|
894
|
+
return /* @__PURE__ */ jsx7(
|
|
895
|
+
Modal,
|
|
896
|
+
{
|
|
897
|
+
destroyOnHidden: true,
|
|
898
|
+
footer: footer ?? null,
|
|
899
|
+
open,
|
|
900
|
+
title,
|
|
901
|
+
width,
|
|
902
|
+
onCancel: onClose,
|
|
903
|
+
styles: {
|
|
904
|
+
root: { minWidth: 0, maxWidth: "100%", boxSizing: "border-box" },
|
|
905
|
+
body: { minWidth: 0, maxWidth: "100%", overflowX: "hidden", boxSizing: "border-box" }
|
|
906
|
+
},
|
|
907
|
+
children: /* @__PURE__ */ jsx7("div", { style: { minWidth: 0, maxWidth: "100%", width: "100%", boxSizing: "border-box" }, children })
|
|
908
|
+
}
|
|
909
|
+
);
|
|
844
910
|
}
|
|
845
911
|
|
|
846
912
|
// src/ui/BestSearch.tsx
|
|
847
913
|
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
|
|
914
|
+
import dayjs4 from "dayjs";
|
|
849
915
|
import { useEffect as useEffect2, useMemo as useMemo4, useRef as useRef2 } from "react";
|
|
850
|
-
import { jsx as jsx8, jsxs as
|
|
916
|
+
import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
851
917
|
function searchFormSignature(fields, initialValues) {
|
|
852
918
|
return JSON.stringify([
|
|
853
919
|
fields.map((field) => ({
|
|
@@ -912,7 +978,7 @@ function FieldControl({ field, value, onChange, ...controlProps }) {
|
|
|
912
978
|
value: toDatePickerValue(value),
|
|
913
979
|
onChange: (date, dateString) => onChange?.(serializeDatePickerValue(date, dateString)),
|
|
914
980
|
disabled: field.disabled,
|
|
915
|
-
disabledDate: (current) => field.maxDate === "today" && current.isAfter(
|
|
981
|
+
disabledDate: (current) => field.maxDate === "today" && current.isAfter(dayjs4(), "day"),
|
|
916
982
|
placeholder: field.placeholder,
|
|
917
983
|
style: { width: "100%" }
|
|
918
984
|
}
|
|
@@ -925,7 +991,7 @@ function FieldControl({ field, value, onChange, ...controlProps }) {
|
|
|
925
991
|
value: toDateRangePickerValue(value),
|
|
926
992
|
onChange: (dates, dateStrings) => onChange?.(serializeDateRangePickerValue(dates, dateStrings)),
|
|
927
993
|
disabled: field.disabled,
|
|
928
|
-
disabledDate: (current) => field.maxDate === "today" && current.isAfter(
|
|
994
|
+
disabledDate: (current) => field.maxDate === "today" && current.isAfter(dayjs4(), "day"),
|
|
929
995
|
style: { width: "100%" }
|
|
930
996
|
}
|
|
931
997
|
);
|
|
@@ -1027,9 +1093,9 @@ function BestSearchBody({
|
|
|
1027
1093
|
onFinish: (values) => onSearch(values),
|
|
1028
1094
|
onValuesChange: (_, values) => onChange?.(values),
|
|
1029
1095
|
className: "best-lowcode-search",
|
|
1030
|
-
children: /* @__PURE__ */
|
|
1096
|
+
children: /* @__PURE__ */ jsxs4(Row, { gutter: 16, align: "bottom", children: [
|
|
1031
1097
|
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__ */
|
|
1098
|
+
/* @__PURE__ */ jsx8(Col, { children: /* @__PURE__ */ jsxs4(Form2.Item, { children: [
|
|
1033
1099
|
/* @__PURE__ */ jsx8(Button3, { htmlType: "submit", loading, type: "primary", children: submitText }),
|
|
1034
1100
|
/* @__PURE__ */ jsx8(
|
|
1035
1101
|
Button3,
|
|
@@ -1052,13 +1118,13 @@ function BestSearchBody({
|
|
|
1052
1118
|
}
|
|
1053
1119
|
|
|
1054
1120
|
// src/ui/BestStates.tsx
|
|
1055
|
-
import { Empty, Result, Spin } from "antd";
|
|
1121
|
+
import { Empty as Empty2, Result, Spin } from "antd";
|
|
1056
1122
|
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
1057
1123
|
function BestLoading({ description = "\u52A0\u8F7D\u4E2D" }) {
|
|
1058
1124
|
return /* @__PURE__ */ jsx9("div", { style: { display: "grid", minHeight: 160, placeItems: "center" }, children: /* @__PURE__ */ jsx9(Spin, { tip: description }) });
|
|
1059
1125
|
}
|
|
1060
1126
|
function BestEmpty({ description = "\u6682\u65E0\u6570\u636E" }) {
|
|
1061
|
-
return /* @__PURE__ */ jsx9(
|
|
1127
|
+
return /* @__PURE__ */ jsx9(Empty2, { description });
|
|
1062
1128
|
}
|
|
1063
1129
|
function BestError({ description = "\u52A0\u8F7D\u5931\u8D25" }) {
|
|
1064
1130
|
return /* @__PURE__ */ jsx9(Result, { status: "error", title: description });
|
|
@@ -1109,9 +1175,9 @@ function BestTable({
|
|
|
1109
1175
|
}
|
|
1110
1176
|
|
|
1111
1177
|
// src/lowcode/runtime.ts
|
|
1112
|
-
import
|
|
1178
|
+
import dayjs5 from "dayjs";
|
|
1113
1179
|
import utc from "dayjs/plugin/utc.js";
|
|
1114
|
-
|
|
1180
|
+
dayjs5.extend(utc);
|
|
1115
1181
|
function toBestListQuery(params, sort) {
|
|
1116
1182
|
const { current, pageSize, ...filters } = params;
|
|
1117
1183
|
const normalizedSort = Object.fromEntries(
|
|
@@ -1144,7 +1210,7 @@ function formatCrudValue(value, format) {
|
|
|
1144
1210
|
const numericValue = typeof value === "number" ? value : Number(value.trim());
|
|
1145
1211
|
timestamp = Number.isFinite(numericValue) && numericValue !== 0 ? Math.abs(numericValue) >= 1e12 ? numericValue : numericValue * 1e3 : value;
|
|
1146
1212
|
}
|
|
1147
|
-
const date =
|
|
1213
|
+
const date = dayjs5.utc(timestamp);
|
|
1148
1214
|
if (!date.isValid()) return String(value);
|
|
1149
1215
|
return date.format(format === "date" ? "YYYY-MM-DD" : "YYYY-MM-DD HH:mm:ss");
|
|
1150
1216
|
}
|
|
@@ -1219,9 +1285,11 @@ var builtInEffects = /* @__PURE__ */ new Set([
|
|
|
1219
1285
|
"openEdit",
|
|
1220
1286
|
"remove",
|
|
1221
1287
|
"runAction",
|
|
1222
|
-
"slot"
|
|
1288
|
+
"slot",
|
|
1289
|
+
"closeDetail"
|
|
1223
1290
|
]);
|
|
1224
1291
|
var columnFormats = /* @__PURE__ */ new Set(["date", "datetime", "money", "text"]);
|
|
1292
|
+
var detailFormats = /* @__PURE__ */ new Set(["text", "number", "money", "date", "datetime", "boolean", "json"]);
|
|
1225
1293
|
function push(diagnostics, path, code, message2) {
|
|
1226
1294
|
diagnostics.push({ path, code, message: message2 });
|
|
1227
1295
|
}
|
|
@@ -1268,6 +1336,14 @@ function validateCondition(condition, path, diagnostics) {
|
|
|
1268
1336
|
}
|
|
1269
1337
|
push(diagnostics, path, "condition.operator", `\u4E0D\u652F\u6301\u7684\u6761\u4EF6\uFF1A${condition.operator}`);
|
|
1270
1338
|
}
|
|
1339
|
+
function validateDetailField(field, path, registry, diagnostics) {
|
|
1340
|
+
if (field.visibleWhen) validateCondition(field.visibleWhen, `${path}/visibleWhen`, diagnostics);
|
|
1341
|
+
if (field.slot && registry && !registry.slots[field.slot])
|
|
1342
|
+
push(diagnostics, `${path}/slot`, "registry.slot", `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${field.slot}`);
|
|
1343
|
+
const format = typeof field.format === "object" ? field.format.type : field.format;
|
|
1344
|
+
if (format && !detailFormats.has(format))
|
|
1345
|
+
push(diagnostics, `${path}/format`, "detail.format", `\u4E0D\u652F\u6301\u7684\u8BE6\u60C5\u683C\u5F0F\uFF1A${format}`);
|
|
1346
|
+
}
|
|
1271
1347
|
function validateFields(fields, path, registry, diagnostics) {
|
|
1272
1348
|
const seen = /* @__PURE__ */ new Set();
|
|
1273
1349
|
fields?.forEach((field, index) => {
|
|
@@ -1421,17 +1497,26 @@ function validateCrudPageSchema(schema, registry) {
|
|
|
1421
1497
|
}
|
|
1422
1498
|
});
|
|
1423
1499
|
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 \
|
|
1500
|
+
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)) {
|
|
1501
|
+
push(diagnostics, "/detail", "detail.type", "detail \u5FC5\u987B\u5305\u542B fields \u6216 sections \u6570\u7EC4");
|
|
1426
1502
|
} else {
|
|
1427
|
-
schema.detail.fields
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
);
|
|
1503
|
+
schema.detail.fields?.forEach((field, index) => validateDetailField(field, `/detail/fields/${index}`, registry, diagnostics));
|
|
1504
|
+
schema.detail.sections?.forEach((section, index) => {
|
|
1505
|
+
if (section.visibleWhen) validateCondition(section.visibleWhen, `/detail/sections/${index}/visibleWhen`, diagnostics);
|
|
1506
|
+
if (!section.key) push(diagnostics, `/detail/sections/${index}/key`, "detail.section.key", "\u8BE6\u60C5\u533A\u5757\u5FC5\u987B\u6307\u5B9A key");
|
|
1507
|
+
if (section.span !== void 0 && (!Number.isInteger(section.span) || section.span < 1))
|
|
1508
|
+
push(diagnostics, `/detail/sections/${index}/span`, "detail.section.span", "\u8BE6\u60C5\u533A\u5757 span \u5FC5\u987B\u662F\u6B63\u6574\u6570");
|
|
1509
|
+
if (section.columns !== void 0 && (!Number.isInteger(section.columns) || section.columns < 1))
|
|
1510
|
+
push(diagnostics, `/detail/sections/${index}/columns`, "detail.section.columns", "\u8BE6\u60C5\u5B57\u6BB5 columns \u5FC5\u987B\u662F\u6B63\u6574\u6570");
|
|
1511
|
+
if (section.layout === "slot" && !section.slot)
|
|
1512
|
+
push(diagnostics, `/detail/sections/${index}/slot`, "detail.slot", "slot \u533A\u5757\u5FC5\u987B\u6307\u5B9A slot");
|
|
1513
|
+
if (section.layout === "table" && !section.table)
|
|
1514
|
+
push(diagnostics, `/detail/sections/${index}/table`, "detail.table", "table \u533A\u5757\u5FC5\u987B\u6307\u5B9A table");
|
|
1515
|
+
if (section.table && typeof section.table.data !== "string")
|
|
1516
|
+
push(diagnostics, `/detail/sections/${index}/table/data`, "detail.table.data", "\u8BE6\u60C5\u8868\u683C data \u5FC5\u987B\u662F\u5B57\u6BB5\u8DEF\u5F84");
|
|
1517
|
+
if (section.slot && registry && !registry.slots[section.slot])
|
|
1518
|
+
push(diagnostics, `/detail/sections/${index}/slot`, "registry.slot", `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${section.slot}`);
|
|
1519
|
+
section.fields?.forEach((field, fieldIndex) => validateDetailField(field, `/detail/sections/${index}/fields/${fieldIndex}`, registry, diagnostics));
|
|
1435
1520
|
});
|
|
1436
1521
|
}
|
|
1437
1522
|
}
|
|
@@ -1449,6 +1534,13 @@ function validateCrudPageSchema(schema, registry) {
|
|
|
1449
1534
|
Boolean(schema.dataSource?.remove),
|
|
1450
1535
|
diagnostics
|
|
1451
1536
|
);
|
|
1537
|
+
validateActions(
|
|
1538
|
+
schema.detail?.footer,
|
|
1539
|
+
"/detail/footer",
|
|
1540
|
+
registry,
|
|
1541
|
+
Boolean(schema.dataSource?.remove),
|
|
1542
|
+
diagnostics
|
|
1543
|
+
);
|
|
1452
1544
|
return { valid: diagnostics.length === 0, diagnostics };
|
|
1453
1545
|
}
|
|
1454
1546
|
function assertValidCrudPageSchema(schema, registry) {
|
|
@@ -1500,7 +1592,7 @@ ${message2}`);
|
|
|
1500
1592
|
}
|
|
1501
1593
|
|
|
1502
1594
|
// src/lowcode/BestCrudPage.tsx
|
|
1503
|
-
import { Fragment as Fragment2, jsx as jsx11, jsxs as
|
|
1595
|
+
import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1504
1596
|
function pickRowKeyValues(record, rowKey) {
|
|
1505
1597
|
if (!record) return {};
|
|
1506
1598
|
const keys = Array.isArray(rowKey) ? rowKey : [rowKey];
|
|
@@ -1573,7 +1665,7 @@ function useFields(fields = []) {
|
|
|
1573
1665
|
const registry = useBestRegistry();
|
|
1574
1666
|
return fields.map((field) => toFieldDefinition(field, registry.dictionaries, registry.slots));
|
|
1575
1667
|
}
|
|
1576
|
-
function toDetailField(field, dictionary, slots) {
|
|
1668
|
+
function toDetailField(field, dictionary, slots, record = {}) {
|
|
1577
1669
|
const slot = field.slot;
|
|
1578
1670
|
const valueEnum = field.dict ? Object.fromEntries(
|
|
1579
1671
|
(dictionary[field.dict] ?? []).map((item) => [String(item.value), item.label])
|
|
@@ -1582,10 +1674,50 @@ function toDetailField(field, dictionary, slots) {
|
|
|
1582
1674
|
field: field.field,
|
|
1583
1675
|
label: field.label,
|
|
1584
1676
|
span: field.span,
|
|
1677
|
+
format: field.format,
|
|
1678
|
+
emptyText: field.emptyText,
|
|
1679
|
+
visible: !field.visibleWhen || evaluateCondition(field.visibleWhen, record, "detail"),
|
|
1585
1680
|
valueEnum,
|
|
1586
|
-
render: slot ? (value,
|
|
1681
|
+
render: slot ? (value, record2) => slots[slot]?.({ field: field.field, record: record2, value }) ?? "-" : void 0
|
|
1587
1682
|
};
|
|
1588
1683
|
}
|
|
1684
|
+
function getPathValue3(values, path) {
|
|
1685
|
+
if (Object.hasOwn(values, path)) return values[path];
|
|
1686
|
+
return path.split(".").reduce((current, part) => {
|
|
1687
|
+
if (current && typeof current === "object") return current[part];
|
|
1688
|
+
return void 0;
|
|
1689
|
+
}, values);
|
|
1690
|
+
}
|
|
1691
|
+
function toDetailSection(section, record, dictionaries, slots) {
|
|
1692
|
+
if (section.visibleWhen && !evaluateCondition(section.visibleWhen, record, "detail")) return null;
|
|
1693
|
+
const fields = section.fields?.map((field) => toDetailField(field, dictionaries, slots, record));
|
|
1694
|
+
const table = section.table ? {
|
|
1695
|
+
key: section.key,
|
|
1696
|
+
data: getPathValue3(record, section.table.data) ?? [],
|
|
1697
|
+
rowKey: section.table.rowKey,
|
|
1698
|
+
scrollX: section.table.scrollX,
|
|
1699
|
+
columns: section.table.columns.map((column) => ({
|
|
1700
|
+
key: column.field,
|
|
1701
|
+
title: column.title,
|
|
1702
|
+
dataIndex: column.field,
|
|
1703
|
+
width: column.width,
|
|
1704
|
+
fixed: column.fixed,
|
|
1705
|
+
render: (value, row) => {
|
|
1706
|
+
if (column.slot) return slots[column.slot]?.({ field: column.field, record: row, value }) ?? "-";
|
|
1707
|
+
if (column.dict) {
|
|
1708
|
+
const item = (dictionaries[column.dict] ?? []).find((candidate) => candidate.value === value);
|
|
1709
|
+
if (item) return item.label;
|
|
1710
|
+
}
|
|
1711
|
+
const format = column.format;
|
|
1712
|
+
if (format === "date" || format === "datetime") return formatCrudValue(value, format);
|
|
1713
|
+
if (format === "money") return formatCrudValue(value, format);
|
|
1714
|
+
return value == null || value === "" ? "-" : String(value);
|
|
1715
|
+
}
|
|
1716
|
+
}))
|
|
1717
|
+
} : void 0;
|
|
1718
|
+
const content = section.layout === "slot" && section.slot ? slots[section.slot]?.({ record }) : void 0;
|
|
1719
|
+
return { key: section.key, title: section.title, description: section.description, columns: section.columns, span: section.span, variant: section.variant, fields, table, content };
|
|
1720
|
+
}
|
|
1589
1721
|
function toTableColumn(column, dictionary, slots) {
|
|
1590
1722
|
const slot = column.slot;
|
|
1591
1723
|
const valueEnum = column.dict ? Object.fromEntries(
|
|
@@ -1631,7 +1763,7 @@ function toProTableSearchColumn(field, dictionary) {
|
|
|
1631
1763
|
initialValue: field.defaultValue,
|
|
1632
1764
|
fieldProps: {
|
|
1633
1765
|
...options ? { options } : {},
|
|
1634
|
-
...field.maxDate === "today" ? { disabledDate: (current) => current.isAfter(
|
|
1766
|
+
...field.maxDate === "today" ? { disabledDate: (current) => current.isAfter(dayjs6(), "day") } : {}
|
|
1635
1767
|
}
|
|
1636
1768
|
};
|
|
1637
1769
|
}
|
|
@@ -1685,14 +1817,44 @@ function BestCrudPage({ adapter, className, schema }) {
|
|
|
1685
1817
|
userTouched: false
|
|
1686
1818
|
});
|
|
1687
1819
|
const [drawer, setDrawer] = useState4({ mode: "closed" });
|
|
1820
|
+
const [detailState, setDetailState] = useState4({ loading: false });
|
|
1821
|
+
const detailRequestRef = useRef3(void 0);
|
|
1688
1822
|
const [submitting, setSubmitting] = useState4(false);
|
|
1689
1823
|
const submittingRef = useRef3(false);
|
|
1690
1824
|
const handleAction = useCallback2(
|
|
1691
1825
|
async (action, record) => {
|
|
1692
1826
|
if (action.access && !registry.access(action.access)) return;
|
|
1827
|
+
if (action.effect === "closeDetail") {
|
|
1828
|
+
detailRequestRef.current?.abort();
|
|
1829
|
+
setDrawer({ mode: "closed" });
|
|
1830
|
+
setDetailState({ loading: false });
|
|
1831
|
+
return;
|
|
1832
|
+
}
|
|
1693
1833
|
if (action.effect !== "remove" && !await confirmBeforeAction(action.confirm, confirmAction))
|
|
1694
1834
|
return;
|
|
1695
|
-
if (action.effect === "openDetail")
|
|
1835
|
+
if (action.effect === "openDetail") {
|
|
1836
|
+
detailRequestRef.current?.abort();
|
|
1837
|
+
const controller = new AbortController();
|
|
1838
|
+
detailRequestRef.current = controller;
|
|
1839
|
+
setDrawer({ mode: "detail", record });
|
|
1840
|
+
setDetailState({ loading: Boolean(schema.dataSource.detail), record });
|
|
1841
|
+
if (schema.dataSource.detail) {
|
|
1842
|
+
const detailService = registry.services[schema.dataSource.detail];
|
|
1843
|
+
if (!detailService) {
|
|
1844
|
+
setDetailState({ loading: false, error: new Error(`\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.detail}`), record });
|
|
1845
|
+
return;
|
|
1846
|
+
}
|
|
1847
|
+
try {
|
|
1848
|
+
const detail = await detailService(record ?? {}, { signal: controller.signal });
|
|
1849
|
+
if (controller.signal.aborted) return;
|
|
1850
|
+
const normalized = isRecord2(detail) ? adapter?.fromDetail ? adapter.fromDetail(detail) : detail : record ?? {};
|
|
1851
|
+
setDetailState({ loading: false, record: normalized });
|
|
1852
|
+
setDrawer({ mode: "detail", record: normalized });
|
|
1853
|
+
} catch (error) {
|
|
1854
|
+
if (!controller.signal.aborted) setDetailState({ loading: false, error, record });
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1696
1858
|
if (action.effect === "openEdit") {
|
|
1697
1859
|
let editRecord = record;
|
|
1698
1860
|
if (schema.dataSource.detail) {
|
|
@@ -1858,7 +2020,7 @@ function BestCrudPage({ adapter, className, schema }) {
|
|
|
1858
2020
|
schema.dataSource.update
|
|
1859
2021
|
]
|
|
1860
2022
|
);
|
|
1861
|
-
return /* @__PURE__ */
|
|
2023
|
+
return /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
1862
2024
|
useBestSearch && searchFields.length ? /* @__PURE__ */ jsx11(
|
|
1863
2025
|
BestSearch,
|
|
1864
2026
|
{
|
|
@@ -1893,22 +2055,41 @@ function BestCrudPage({ adapter, className, schema }) {
|
|
|
1893
2055
|
toolBarRender: () => schema.toolbar?.map((action) => /* @__PURE__ */ jsx11(ActionButton, { action, onExecute: handleAction }, action.id)) ?? []
|
|
1894
2056
|
}
|
|
1895
2057
|
),
|
|
1896
|
-
/* @__PURE__ */
|
|
2058
|
+
drawer.mode === "detail" && schema.detail?.mode === "inline" ? /* @__PURE__ */ jsx11(DetailContent, { state: detailState, record: drawer.record }) : null,
|
|
2059
|
+
drawer.mode !== "closed" && (schema.detail?.mode !== "inline" || drawer.mode !== "detail") && schema.detail?.mode === "drawer" ? /* @__PURE__ */ jsxs5(
|
|
2060
|
+
BestDrawer,
|
|
2061
|
+
{
|
|
2062
|
+
open: true,
|
|
2063
|
+
width: schema.detail.width,
|
|
2064
|
+
title: drawer.mode === "detail" ? `${schema.title}\u8BE6\u60C5` : drawer.mode === "edit" ? `\u7F16\u8F91${schema.title}` : `\u65B0\u5EFA${schema.title}`,
|
|
2065
|
+
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,
|
|
2066
|
+
onClose: () => {
|
|
2067
|
+
detailRequestRef.current?.abort();
|
|
2068
|
+
setDrawer({ mode: "closed" });
|
|
2069
|
+
setDetailState({ loading: false });
|
|
2070
|
+
},
|
|
2071
|
+
children: [
|
|
2072
|
+
drawer.mode === "detail" ? /* @__PURE__ */ jsx11(DetailContent, { state: detailState, record: drawer.record }) : null,
|
|
2073
|
+
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) => {
|
|
2074
|
+
void submitForm(values);
|
|
2075
|
+
} }) : null
|
|
2076
|
+
]
|
|
2077
|
+
}
|
|
2078
|
+
) : null,
|
|
2079
|
+
drawer.mode !== "closed" && (schema.detail?.mode !== "inline" || drawer.mode !== "detail") && schema.detail?.mode !== "drawer" ? /* @__PURE__ */ jsxs5(
|
|
1897
2080
|
BestModal,
|
|
1898
2081
|
{
|
|
1899
|
-
open:
|
|
2082
|
+
open: true,
|
|
1900
2083
|
title: drawer.mode === "detail" ? `${schema.title}\u8BE6\u60C5` : drawer.mode === "edit" ? `\u7F16\u8F91${schema.title}` : `\u65B0\u5EFA${schema.title}`,
|
|
1901
|
-
|
|
2084
|
+
width: schema.detail?.width,
|
|
2085
|
+
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,
|
|
2086
|
+
onClose: () => {
|
|
2087
|
+
detailRequestRef.current?.abort();
|
|
2088
|
+
setDrawer({ mode: "closed" });
|
|
2089
|
+
setDetailState({ loading: false });
|
|
2090
|
+
},
|
|
1902
2091
|
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,
|
|
2092
|
+
drawer.mode === "detail" ? /* @__PURE__ */ jsx11(DetailContent, { state: detailState, record: drawer.record }) : null,
|
|
1912
2093
|
drawer.mode === "edit" || drawer.mode === "create" ? /* @__PURE__ */ jsx11(
|
|
1913
2094
|
BestForm,
|
|
1914
2095
|
{
|
|
@@ -1924,8 +2105,24 @@ function BestCrudPage({ adapter, className, schema }) {
|
|
|
1924
2105
|
) : null
|
|
1925
2106
|
]
|
|
1926
2107
|
}
|
|
1927
|
-
)
|
|
2108
|
+
) : null
|
|
1928
2109
|
] });
|
|
2110
|
+
function DetailContent({ state, record }) {
|
|
2111
|
+
if (state.loading) return /* @__PURE__ */ jsx11(BestLoading, {});
|
|
2112
|
+
if (state.error) return /* @__PURE__ */ jsx11(BestError, { description: errorMessage(state.error, `${schema.title}\u8BE6\u60C5\u52A0\u8F7D\u5931\u8D25`) });
|
|
2113
|
+
if (!record) return /* @__PURE__ */ jsx11(BestEmpty, {});
|
|
2114
|
+
const sections = schema.detail?.sections?.map((section) => toDetailSection(section, record, registry.dictionaries, registry.slots)).filter(Boolean);
|
|
2115
|
+
return /* @__PURE__ */ jsx11(
|
|
2116
|
+
BestDetail,
|
|
2117
|
+
{
|
|
2118
|
+
fields: schema.detail?.fields?.map((field) => toDetailField(field, registry.dictionaries, registry.slots, record)) ?? [],
|
|
2119
|
+
sections,
|
|
2120
|
+
sectionColumns: schema.detail?.columns,
|
|
2121
|
+
sectionGap: schema.detail?.gap,
|
|
2122
|
+
record
|
|
2123
|
+
}
|
|
2124
|
+
);
|
|
2125
|
+
}
|
|
1929
2126
|
function ActionButton({
|
|
1930
2127
|
action,
|
|
1931
2128
|
record,
|