best-lowcode-runtime 0.2.10 → 0.2.12

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/README.md CHANGED
@@ -44,6 +44,30 @@ export function CustomerPage() {
44
44
  }
45
45
  ```
46
46
 
47
+ ### 组合列
48
+
49
+ 表格列可以通过 `composite` 在 JSON Schema 中组合多个记录字段,无需编写 Slot:
50
+
51
+ ```ts
52
+ table: {
53
+ rowKey: 'id',
54
+ columns: [{
55
+ title: '客户信息',
56
+ width: 220,
57
+ composite: {
58
+ layout: 'vertical',
59
+ items: [
60
+ { label: '客户ID', field: 'customerId' },
61
+ { label: '姓名', field: 'customerName', emptyText: '--' },
62
+ { label: '邮箱', field: 'customerEmail' }
63
+ ]
64
+ }
65
+ }]
66
+ }
67
+ ```
68
+
69
+ `composite.items` 支持 `label`、`dict`、`format` 和 `emptyText`;组合列也可以继续使用普通列的 `width` 和 `fixed` 配置。
70
+
47
71
  ## 异步字典更新
48
72
 
49
73
  字典可以在页面初始化后通过 `useBestDictionaryActions` 局部更新,不需要替换完整 Registry:
package/dist/dev.js CHANGED
@@ -200,6 +200,50 @@ function validateCrudPageSchema(schema, registry) {
200
200
  if (!schema.table?.columns?.length)
201
201
  push(diagnostics, "/table/columns", "table.columns", "\u81F3\u5C11\u9700\u8981\u4E00\u5217");
202
202
  schema.table?.columns?.forEach((column, index) => {
203
+ if (!column.field && !column.composite) {
204
+ push(
205
+ diagnostics,
206
+ `/table/columns/${index}`,
207
+ "column.field",
208
+ "\u666E\u901A\u5217\u5FC5\u987B\u6307\u5B9A field\uFF0C\u7EC4\u5408\u5217\u5FC5\u987B\u6307\u5B9A composite"
209
+ );
210
+ }
211
+ if (column.composite) {
212
+ if (!column.composite.items?.length) {
213
+ push(
214
+ diagnostics,
215
+ `/table/columns/${index}/composite/items`,
216
+ "column.composite.items",
217
+ "\u7EC4\u5408\u5217\u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u5B57\u6BB5"
218
+ );
219
+ }
220
+ column.composite.items?.forEach((item, itemIndex) => {
221
+ if (!item.field) {
222
+ push(
223
+ diagnostics,
224
+ `/table/columns/${index}/composite/items/${itemIndex}/field`,
225
+ "column.composite.field",
226
+ "\u7EC4\u5408\u5217\u5B57\u6BB5\u4E0D\u80FD\u4E3A\u7A7A"
227
+ );
228
+ }
229
+ if (item.format && !columnFormats.has(item.format)) {
230
+ push(
231
+ diagnostics,
232
+ `/table/columns/${index}/composite/items/${itemIndex}/format`,
233
+ "column.composite.format",
234
+ `\u4E0D\u652F\u6301\u7684\u683C\u5F0F\uFF1A${item.format}`
235
+ );
236
+ }
237
+ if (item.dict && registry && !registry.dictionaries[item.dict]) {
238
+ push(
239
+ diagnostics,
240
+ `/table/columns/${index}/composite/items/${itemIndex}/dict`,
241
+ "registry.dictionary",
242
+ `\u672A\u6CE8\u518C\u5B57\u5178\uFF1A${item.dict}`
243
+ );
244
+ }
245
+ });
246
+ }
203
247
  if (column.fixed !== void 0 && column.fixed !== "left" && column.fixed !== "right") {
204
248
  push(
205
249
  diagnostics,
package/dist/dev.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/lowcode/schema.ts", "../src/lowcode/validate.ts", "../src/lowcode/dev.ts"],
4
- "sourcesContent": ["import type { BestFieldComponent, BestFieldRule } from '../ui/types'\n\nexport const CRUD_SCHEMA_ID = 'https://best.dev/schema/crud/v1' as const\nexport const CRUD_SCHEMA_VERSION = 1 as const\nexport const TABBED_PAGE_SCHEMA_ID = 'https://best.dev/schema/tabs/v1' as const\nexport const TABBED_PAGE_SCHEMA_VERSION = 1 as const\n\nexport type Condition =\n | { operator: 'equals'; field: string; value: string | number | boolean | null }\n | { operator: 'notEmpty'; field: string }\n | { operator: 'modeEquals'; value: FormMode }\n | { operator: 'and' | 'or'; conditions: Condition[] }\n | { operator: 'not'; condition: Condition }\n\nexport type FormMode = 'create' | 'edit' | 'detail'\n\nexport type FieldSchema = {\n field: string\n label: string\n component: BestFieldComponent\n placeholder?: string\n dict?: string\n required?: boolean\n disabled?: boolean\n hidden?: boolean\n maxDate?: 'today'\n span?: number\n defaultValue?: string | number | boolean | null\n rules?: BestFieldRule[]\n /** Application-specific form control registered in the BestProvider registry. */\n slot?: string\n remoteService?: string\n searchField?: string\n labelField?: string\n valueField?: string\n debounceMs?: number\n pageSize?: number\n visibleWhen?: Condition\n disabledWhen?: Condition\n /** Clears stale dependent values when this field becomes hidden. */\n clearWhenHidden?: boolean\n /** Repeated object fields, for rules such as tiered pricing. */\n itemFields?: Omit<FieldSchema, 'itemFields'>[]\n minItems?: number\n maxItems?: number\n}\n\nexport type TableColumnSchema = {\n field: string\n title: string\n dict?: string\n width?: number\n fixed?: 'left' | 'right'\n format?: 'date' | 'datetime' | 'money' | 'text'\n slot?: string\n}\n\nexport type DetailFieldSchema = {\n field: string\n label: string\n dict?: string\n span?: number\n slot?: string\n format?: DetailFormat | DetailFormatConfig\n visibleWhen?: Condition\n emptyText?: string\n}\n\nexport type DetailFormat = 'text' | 'number' | 'money' | 'date' | 'datetime' | 'boolean' | 'json'\n\nexport type DetailFormatConfig = {\n type: DetailFormat\n emptyText?: string\n precision?: number\n timezone?: string\n}\n\nexport type DetailTableColumnSchema = {\n field: string\n title: string\n width?: number\n fixed?: 'left' | 'right'\n dict?: string\n format?: DetailFormat | DetailFormatConfig\n slot?: string\n}\n\nexport type DetailTableSchema = {\n data: string\n rowKey?: string\n columns: DetailTableColumnSchema[]\n scrollX?: number | string\n}\n\nexport type DetailSectionSchema = {\n key: string\n title?: string\n description?: string\n visibleWhen?: Condition\n layout?: 'fields' | 'table' | 'slot'\n columns?: number\n span?: number\n variant?: 'plain' | 'card'\n fields?: DetailFieldSchema[]\n table?: DetailTableSchema\n slot?: string\n}\n\nexport type PageActionButtonType = 'primary' | 'default' | 'link' | 'text' | 'dashed'\n\nexport type PageActionSchema = {\n id: string\n label: string\n effect: 'openCreate' | 'openDetail' | 'openEdit' | 'remove' | 'runAction' | 'slot' | 'closeDetail'\n action?: string\n slot?: string\n access?: string\n confirm?: string\n /** Visual button style; omitted actions use the runtime area default. */\n buttonType?: PageActionButtonType\n}\n\nexport type CrudPageSchema = {\n $schema: typeof CRUD_SCHEMA_ID\n version: typeof CRUD_SCHEMA_VERSION\n id: string\n kind: 'crud'\n title: string\n dataSource: {\n list: string\n detail?: string\n create?: string\n update?: string\n remove?: string\n }\n search?: FieldSchema[]\n searchMode?: 'proTable' | 'bestSearch'\n form?: FieldSchema[]\n table: {\n rowKey: string | string[]\n columns: TableColumnSchema[]\n actions?: PageActionSchema[]\n scrollX?: number\n pageSize?: number\n }\n detail?: {\n mode?: 'drawer' | 'modal' | 'inline'\n width?: number | string\n columns?: number\n gap?: number | string\n fields?: DetailFieldSchema[]\n sections?: DetailSectionSchema[]\n footer?: PageActionSchema[]\n }\n toolbar?: PageActionSchema[]\n meta?: {\n generatedBy?: string\n generatedAt?: string\n }\n}\n\nexport type TabContentSchema =\n | { type: 'crud'; schema: CrudPageSchema }\n | { type: 'slot'; slot: string }\n\nexport type TabSchema = {\n key: string\n label: string\n access?: string\n /** Defaults to true so inactive CRUD pages do not fetch until selected. */\n destroyOnHidden?: boolean\n content: TabContentSchema\n}\n\n/** A page composition schema with runtime-owned tab navigation. */\nexport type TabbedPageSchema = {\n $schema: typeof TABBED_PAGE_SCHEMA_ID\n version: typeof TABBED_PAGE_SCHEMA_VERSION\n id: string\n kind: 'tabs'\n tabs: TabSchema[]\n}\n", "import type { BestRegistry } from '../runtime'\nimport {\n type Condition,\n CRUD_SCHEMA_ID,\n CRUD_SCHEMA_VERSION,\n type CrudPageSchema,\n type FieldSchema,\n type PageActionSchema,\n TABBED_PAGE_SCHEMA_ID,\n TABBED_PAGE_SCHEMA_VERSION,\n type TabbedPageSchema\n} from './schema'\n\nexport type SchemaDiagnostic = {\n path: string\n code: string\n message: string\n}\n\nexport type SchemaValidationResult = {\n valid: boolean\n diagnostics: SchemaDiagnostic[]\n}\n\nconst fieldComponents = new Set([\n 'input',\n 'number',\n 'select',\n 'remoteSelect',\n 'date',\n 'dateRange',\n 'textarea',\n 'slot',\n 'repeatable'\n])\nconst builtInEffects = new Set([\n 'openCreate',\n 'openDetail',\n 'openEdit',\n 'remove',\n 'runAction',\n 'slot',\n 'closeDetail'\n])\nconst columnFormats = new Set(['date', 'datetime', 'money', 'text'])\nconst detailFormats = new Set(['text', 'number', 'money', 'date', 'datetime', 'boolean', 'json'])\n\nfunction push(diagnostics: SchemaDiagnostic[], path: string, code: string, message: string) {\n diagnostics.push({ path, code, message })\n}\n\nfunction validateCondition(condition: Condition, path: string, diagnostics: SchemaDiagnostic[]) {\n if (!condition || typeof condition !== 'object') {\n push(diagnostics, path, 'condition.type', '\u6761\u4EF6\u5FC5\u987B\u662F\u5BF9\u8C61')\n return\n }\n if (condition.operator === 'equals') {\n if (typeof condition.field !== 'string' || condition.field === '') {\n push(diagnostics, path, 'condition.field', 'equals \u6761\u4EF6\u5FC5\u987B\u6307\u5B9A\u5B57\u6BB5\u540D')\n }\n return\n }\n if (condition.operator === 'notEmpty') {\n if (typeof condition.field !== 'string' || condition.field === '') {\n push(diagnostics, path, 'condition.field', 'notEmpty \u6761\u4EF6\u5FC5\u987B\u6307\u5B9A\u5B57\u6BB5\u540D')\n }\n return\n }\n if (condition.operator === 'modeEquals') {\n return\n }\n if (\n (condition.operator === 'and' || condition.operator === 'or') &&\n !Array.isArray(condition.conditions)\n ) {\n push(diagnostics, path, 'condition.conditions', '\u7EC4\u5408\u6761\u4EF6\u5FC5\u987B\u6307\u5B9A conditions \u6570\u7EC4')\n return\n }\n if (condition.operator === 'and' || condition.operator === 'or') {\n if (condition.conditions.length === 0) {\n push(diagnostics, path, 'condition.empty', '\u7EC4\u5408\u6761\u4EF6\u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u5B50\u6761\u4EF6')\n }\n condition.conditions.forEach((item, index) => {\n validateCondition(item, `${path}/conditions/${index}`, diagnostics)\n })\n return\n }\n if (condition.operator === 'not') {\n if (!condition.condition) {\n push(diagnostics, path, 'condition.missing', 'not \u6761\u4EF6\u5FC5\u987B\u6307\u5B9A condition')\n return\n }\n validateCondition(condition.condition, `${path}/condition`, diagnostics)\n return\n }\n push(diagnostics, path, 'condition.operator', `\u4E0D\u652F\u6301\u7684\u6761\u4EF6\uFF1A${(condition as { operator?: unknown }).operator}`)\n}\n\nfunction validateDetailField(\n field: import('./schema').DetailFieldSchema,\n path: string,\n registry: BestRegistry | undefined,\n diagnostics: SchemaDiagnostic[]\n) {\n if (field.visibleWhen) validateCondition(field.visibleWhen, `${path}/visibleWhen`, diagnostics)\n if (field.slot && registry && !registry.slots[field.slot])\n push(diagnostics, `${path}/slot`, 'registry.slot', `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${field.slot}`)\n const format = typeof field.format === 'object' ? field.format.type : field.format\n if (format && !detailFormats.has(format))\n push(diagnostics, `${path}/format`, 'detail.format', `\u4E0D\u652F\u6301\u7684\u8BE6\u60C5\u683C\u5F0F\uFF1A${format}`)\n}\n\nfunction validateFields(\n fields: FieldSchema[] | undefined,\n path: string,\n registry: BestRegistry | undefined,\n diagnostics: SchemaDiagnostic[]\n) {\n const seen = new Set<string>()\n fields?.forEach((field, index) => {\n const fieldPath = `${path}/${index}`\n if (!field.field) push(diagnostics, fieldPath, 'field.missing', '\u5B57\u6BB5\u540D\u4E0D\u80FD\u4E3A\u7A7A')\n if (seen.has(field.field))\n push(diagnostics, fieldPath, 'field.duplicate', `\u5B57\u6BB5\u91CD\u590D\uFF1A${field.field}`)\n seen.add(field.field)\n if (!fieldComponents.has(field.component))\n push(diagnostics, fieldPath, 'field.component', `\u4E0D\u652F\u6301\u7684\u7EC4\u4EF6\uFF1A${field.component}`)\n if (field.dict && registry && !registry.dictionaries[field.dict]) {\n push(diagnostics, fieldPath, 'registry.dictionary', `\u672A\u6CE8\u518C\u5B57\u5178\uFF1A${field.dict}`)\n }\n if (field.component === 'remoteSelect' && !field.remoteService)\n push(diagnostics, fieldPath, 'field.remoteService', 'remoteSelect \u5FC5\u987B\u6307\u5B9A remoteService')\n if (field.remoteService && registry && !registry.services[field.remoteService])\n push(diagnostics, fieldPath, 'registry.service', `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${field.remoteService}`)\n if (field.component === 'slot' && !field.slot)\n push(diagnostics, fieldPath, 'field.slot', 'slot \u7EC4\u4EF6\u5FC5\u987B\u6307\u5B9A slot key')\n if (field.component === 'repeatable' && !field.itemFields?.length)\n push(\n diagnostics,\n fieldPath,\n 'field.repeatable',\n 'repeatable \u7EC4\u4EF6\u81F3\u5C11\u9700\u8981\u4E00\u4E2A itemFields \u5B57\u6BB5'\n )\n if (field.itemFields?.length)\n validateFields(\n field.itemFields as FieldSchema[],\n `${fieldPath}/itemFields`,\n registry,\n diagnostics\n )\n if (\n field.minItems !== undefined &&\n field.maxItems !== undefined &&\n field.minItems > field.maxItems\n )\n push(diagnostics, fieldPath, 'field.repeatable.range', 'minItems \u4E0D\u80FD\u5927\u4E8E maxItems')\n if (field.slot && registry && !registry.slots[field.slot])\n push(diagnostics, fieldPath, 'registry.slot', `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${field.slot}`)\n if (field.visibleWhen)\n validateCondition(field.visibleWhen, `${fieldPath}/visibleWhen`, diagnostics)\n if (field.disabledWhen)\n validateCondition(field.disabledWhen, `${fieldPath}/disabledWhen`, diagnostics)\n })\n}\n\nfunction validateActions(\n actions: PageActionSchema[] | undefined,\n path: string,\n registry: BestRegistry | undefined,\n hasRemoveService: boolean,\n diagnostics: SchemaDiagnostic[]\n) {\n actions?.forEach((action, index) => {\n const actionPath = `${path}/${index}`\n if (!action.id) push(diagnostics, actionPath, 'action.missing', '\u52A8\u4F5C id \u4E0D\u80FD\u4E3A\u7A7A')\n if (!builtInEffects.has(action.effect))\n push(diagnostics, actionPath, 'action.effect', `\u4E0D\u652F\u6301\u7684\u52A8\u4F5C\uFF1A${action.effect}`)\n if (action.effect === 'runAction' && !action.action)\n push(diagnostics, actionPath, 'action.key', 'runAction \u5FC5\u987B\u6307\u5B9A action key')\n if (action.effect === 'remove' && !hasRemoveService)\n push(diagnostics, actionPath, 'action.removeService', 'remove \u52A8\u4F5C\u5FC5\u987B\u914D\u7F6E dataSource.remove')\n if (action.effect === 'slot' && !action.slot)\n push(diagnostics, actionPath, 'action.slot', 'slot \u52A8\u4F5C\u5FC5\u987B\u6307\u5B9A slot key')\n if (action.action && registry && !registry.actions[action.action]) {\n push(diagnostics, actionPath, 'registry.action', `\u672A\u6CE8\u518C\u52A8\u4F5C\uFF1A${action.action}`)\n }\n if (action.slot && registry && !registry.slots[action.slot]) {\n push(diagnostics, actionPath, 'registry.slot', `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${action.slot}`)\n }\n })\n}\n\nexport function validateCrudPageSchema(\n schema: CrudPageSchema,\n registry?: BestRegistry\n): SchemaValidationResult {\n const diagnostics: SchemaDiagnostic[] = []\n if (schema.$schema !== CRUD_SCHEMA_ID)\n push(diagnostics, '/$schema', 'schema.id', `\u4EC5\u652F\u6301 ${CRUD_SCHEMA_ID}`)\n if (schema.version !== CRUD_SCHEMA_VERSION)\n push(diagnostics, '/version', 'schema.version', `\u4EC5\u652F\u6301\u7248\u672C ${CRUD_SCHEMA_VERSION}`)\n if (!schema.id) push(diagnostics, '/id', 'page.id', '\u9875\u9762 id \u4E0D\u80FD\u4E3A\u7A7A')\n if (!schema.title) push(diagnostics, '/title', 'page.title', '\u9875\u9762\u6807\u9898\u4E0D\u80FD\u4E3A\u7A7A')\n if (!schema.dataSource?.list)\n push(diagnostics, '/dataSource/list', 'service.list', '\u5217\u8868\u670D\u52A1\u4E0D\u80FD\u4E3A\u7A7A')\n if (schema.dataSource?.list && registry && !registry.listServices[schema.dataSource.list]) {\n push(\n diagnostics,\n '/dataSource/list',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.list}`\n )\n }\n if (schema.dataSource?.detail && registry && !registry.services[schema.dataSource.detail]) {\n push(\n diagnostics,\n '/dataSource/detail',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.detail}`\n )\n }\n if (schema.dataSource?.create && registry && !registry.services[schema.dataSource.create]) {\n push(\n diagnostics,\n '/dataSource/create',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.create}`\n )\n }\n if (schema.dataSource?.update && registry && !registry.services[schema.dataSource.update]) {\n push(\n diagnostics,\n '/dataSource/update',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.update}`\n )\n }\n if (schema.dataSource?.remove && registry && !registry.services[schema.dataSource.remove]) {\n push(\n diagnostics,\n '/dataSource/remove',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.remove}`\n )\n }\n validateFields(schema.search, '/search', registry, diagnostics)\n validateFields(schema.form, '/form', registry, diagnostics)\n if (!schema.table?.rowKey) push(diagnostics, '/table/rowKey', 'table.rowKey', 'rowKey \u4E0D\u80FD\u4E3A\u7A7A')\n if (!schema.table?.columns?.length)\n push(diagnostics, '/table/columns', 'table.columns', '\u81F3\u5C11\u9700\u8981\u4E00\u5217')\n schema.table?.columns?.forEach((column, index) => {\n if (column.fixed !== undefined && column.fixed !== 'left' && column.fixed !== 'right') {\n push(\n diagnostics,\n `/table/columns/${index}/fixed`,\n 'column.fixed',\n `\u4E0D\u652F\u6301\u7684\u56FA\u5B9A\u4F4D\u7F6E\uFF1A${column.fixed}`\n )\n }\n if (column.format && !columnFormats.has(column.format)) {\n push(\n diagnostics,\n `/table/columns/${index}/format`,\n 'column.format',\n `\u4E0D\u652F\u6301\u7684\u683C\u5F0F\uFF1A${column.format}`\n )\n }\n if (column.dict && registry && !registry.dictionaries[column.dict]) {\n push(\n diagnostics,\n `/table/columns/${index}/dict`,\n 'registry.dictionary',\n `\u672A\u6CE8\u518C\u5B57\u5178\uFF1A${column.dict}`\n )\n }\n if (column.slot && registry && !registry.slots[column.slot]) {\n push(\n diagnostics,\n `/table/columns/${index}/slot`,\n 'registry.slot',\n `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${column.slot}`\n )\n }\n })\n if (schema.detail !== undefined) {\n if (\n !schema.detail ||\n typeof schema.detail !== 'object' ||\n (schema.detail.fields !== undefined && !Array.isArray(schema.detail.fields)) ||\n (schema.detail.sections !== undefined && !Array.isArray(schema.detail.sections))\n ) {\n push(diagnostics, '/detail', 'detail.type', 'detail \u5FC5\u987B\u5305\u542B fields \u6216 sections \u6570\u7EC4')\n } else {\n schema.detail.fields?.forEach((field, index) => validateDetailField(field, `/detail/fields/${index}`, registry, diagnostics))\n schema.detail.sections?.forEach((section, index) => {\n if (section.visibleWhen) validateCondition(section.visibleWhen, `/detail/sections/${index}/visibleWhen`, diagnostics)\n if (!section.key) push(diagnostics, `/detail/sections/${index}/key`, 'detail.section.key', '\u8BE6\u60C5\u533A\u5757\u5FC5\u987B\u6307\u5B9A key')\n if (section.span !== undefined && (!Number.isInteger(section.span) || section.span < 1))\n push(diagnostics, `/detail/sections/${index}/span`, 'detail.section.span', '\u8BE6\u60C5\u533A\u5757 span \u5FC5\u987B\u662F\u6B63\u6574\u6570')\n if (section.columns !== undefined && (!Number.isInteger(section.columns) || section.columns < 1))\n push(diagnostics, `/detail/sections/${index}/columns`, 'detail.section.columns', '\u8BE6\u60C5\u5B57\u6BB5 columns \u5FC5\u987B\u662F\u6B63\u6574\u6570')\n if (section.layout === 'slot' && !section.slot)\n push(diagnostics, `/detail/sections/${index}/slot`, 'detail.slot', 'slot \u533A\u5757\u5FC5\u987B\u6307\u5B9A slot')\n if (section.layout === 'table' && !section.table)\n push(diagnostics, `/detail/sections/${index}/table`, 'detail.table', 'table \u533A\u5757\u5FC5\u987B\u6307\u5B9A table')\n if (section.table && typeof section.table.data !== 'string')\n push(diagnostics, `/detail/sections/${index}/table/data`, 'detail.table.data', '\u8BE6\u60C5\u8868\u683C data \u5FC5\u987B\u662F\u5B57\u6BB5\u8DEF\u5F84')\n if (section.slot && registry && !registry.slots[section.slot])\n push(diagnostics, `/detail/sections/${index}/slot`, 'registry.slot', `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${section.slot}`)\n section.fields?.forEach((field, fieldIndex) => validateDetailField(field, `/detail/sections/${index}/fields/${fieldIndex}`, registry, diagnostics))\n })\n }\n }\n validateActions(\n schema.table?.actions,\n '/table/actions',\n registry,\n Boolean(schema.dataSource?.remove),\n diagnostics\n )\n validateActions(\n schema.toolbar,\n '/toolbar',\n registry,\n Boolean(schema.dataSource?.remove),\n diagnostics\n )\n validateActions(\n schema.detail?.footer,\n '/detail/footer',\n registry,\n Boolean(schema.dataSource?.remove),\n diagnostics\n )\n return { valid: diagnostics.length === 0, diagnostics }\n}\n\nexport function assertValidCrudPageSchema(schema: CrudPageSchema, registry?: BestRegistry) {\n const result = validateCrudPageSchema(schema, registry)\n if (!result.valid) {\n const message = result.diagnostics.map((item) => `${item.path}: ${item.message}`).join('\\n')\n throw new Error(`Schema \u6821\u9A8C\u5931\u8D25\uFF1A\\n${message}`)\n }\n}\n\nexport function validateTabbedPageSchema(\n schema: TabbedPageSchema,\n registry?: BestRegistry\n): SchemaValidationResult {\n const diagnostics: SchemaDiagnostic[] = []\n if (schema.$schema !== TABBED_PAGE_SCHEMA_ID)\n push(diagnostics, '/$schema', 'schema.id', `\u4EC5\u652F\u6301 ${TABBED_PAGE_SCHEMA_ID}`)\n if (schema.version !== TABBED_PAGE_SCHEMA_VERSION)\n push(diagnostics, '/version', 'schema.version', `\u4EC5\u652F\u6301\u7248\u672C ${TABBED_PAGE_SCHEMA_VERSION}`)\n if (!schema.id) push(diagnostics, '/id', 'page.id', '\u9875\u9762 id \u4E0D\u80FD\u4E3A\u7A7A')\n if (!Array.isArray(schema.tabs) || schema.tabs.length === 0) {\n push(diagnostics, '/tabs', 'tabs.required', '\u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u9875\u7B7E')\n return { valid: false, diagnostics }\n }\n const keys = new Set<string>()\n schema.tabs.forEach((tab, index) => {\n const path = `/tabs/${index}`\n if (!tab.key) push(diagnostics, path, 'tab.key', '\u9875\u7B7E key \u4E0D\u80FD\u4E3A\u7A7A')\n if (keys.has(tab.key)) push(diagnostics, path, 'tab.duplicate', `\u9875\u7B7E key \u91CD\u590D\uFF1A${tab.key}`)\n keys.add(tab.key)\n if (!tab.label) push(diagnostics, path, 'tab.label', '\u9875\u7B7E\u6807\u9898\u4E0D\u80FD\u4E3A\u7A7A')\n if (tab.content.type === 'crud') {\n const result = validateCrudPageSchema(tab.content.schema, registry)\n diagnostics.push(...result.diagnostics.map((item) => ({ ...item, path: `${path}/content/schema${item.path}` })))\n } else if (tab.content.type === 'slot') {\n if (!tab.content.slot) push(diagnostics, path, 'tab.slot', 'slot \u9875\u7B7E\u5FC5\u987B\u6307\u5B9A slot key')\n if (tab.content.slot && registry && !registry.slots[tab.content.slot])\n push(diagnostics, path, 'registry.slot', `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${tab.content.slot}`)\n } else {\n push(diagnostics, path, 'tab.content', '\u4E0D\u652F\u6301\u7684\u9875\u7B7E\u5185\u5BB9\u7C7B\u578B')\n }\n })\n return { valid: diagnostics.length === 0, diagnostics }\n}\n\nexport function assertValidTabbedPageSchema(schema: TabbedPageSchema, registry?: BestRegistry) {\n const result = validateTabbedPageSchema(schema, registry)\n if (!result.valid) {\n const message = result.diagnostics.map((item) => `${item.path}: ${item.message}`).join('\\n')\n throw new Error(`Schema \u6821\u9A8C\u5931\u8D25\uFF1A\\n${message}`)\n }\n}\n", "import {\n CRUD_SCHEMA_ID,\n TABBED_PAGE_SCHEMA_ID\n} from './schema'\nimport type {\n CRUD_SCHEMA_VERSION,\n CrudPageSchema,\n FieldSchema,\n PageActionSchema,\n TABBED_PAGE_SCHEMA_VERSION,\n TabbedPageSchema\n} from './schema'\nimport type { SchemaDiagnostic, SchemaValidationResult } from './validate'\nimport { validateCrudPageSchema, validateTabbedPageSchema } from './validate'\n\nconst builtInCapabilities = [\n 'builtin.effect.openCreate',\n 'builtin.effect.openDetail',\n 'builtin.effect.openEdit',\n 'builtin.effect.remove',\n 'builtin.effect.runAction',\n 'builtin.effect.slot',\n 'builtin.effect.closeDetail',\n 'builtin.format.date',\n 'builtin.format.datetime',\n 'builtin.format.money',\n 'builtin.format.text',\n 'builtin.field.input',\n 'builtin.field.number',\n 'builtin.field.select',\n 'builtin.field.remoteSelect',\n 'builtin.field.date',\n 'builtin.field.dateRange',\n 'builtin.field.textarea',\n 'builtin.field.slot',\n 'builtin.field.repeatable'\n] as const\n\ntype JsonRecord = Record<string, unknown>\n\nfunction isRecord(value: unknown): value is JsonRecord {\n return !!value && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction arrayOfRecords(value: unknown): JsonRecord[] | undefined {\n return Array.isArray(value) && value.every(isRecord) ? value : undefined\n}\n\nfunction diagnostic(path: string, code: string, message: string): SchemaDiagnostic {\n return { path, code, message }\n}\n\nfunction validateUnknownShape(candidate: unknown): SchemaDiagnostic[] {\n if (!isRecord(candidate)) return [diagnostic('', 'schema.type', 'Schema \u5FC5\u987B\u662F JSON \u5BF9\u8C61')]\n const diagnostics: SchemaDiagnostic[] = []\n if (!isRecord(candidate.dataSource))\n diagnostics.push(diagnostic('/dataSource', 'dataSource.type', 'dataSource \u5FC5\u987B\u662F\u5BF9\u8C61'))\n if (!isRecord(candidate.table))\n diagnostics.push(diagnostic('/table', 'table.type', 'table \u5FC5\u987B\u662F\u5BF9\u8C61'))\n for (const key of ['search', 'form'] as const) {\n if (candidate[key] !== undefined && !arrayOfRecords(candidate[key])) {\n diagnostics.push(diagnostic(`/${key}`, 'field.list', `${key} \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4`))\n }\n }\n if (isRecord(candidate.table)) {\n if (!arrayOfRecords(candidate.table.columns)) {\n diagnostics.push(diagnostic('/table/columns', 'column.list', 'columns \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4'))\n }\n if (candidate.table.actions !== undefined && !arrayOfRecords(candidate.table.actions)) {\n diagnostics.push(diagnostic('/table/actions', 'action.list', 'actions \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4'))\n }\n }\n if (candidate.toolbar !== undefined && !arrayOfRecords(candidate.toolbar)) {\n diagnostics.push(diagnostic('/toolbar', 'action.list', 'toolbar \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4'))\n }\n return diagnostics\n}\n\nfunction toRuntimeSchema(candidate: JsonRecord): CrudPageSchema {\n return {\n $schema: candidate.$schema as typeof CRUD_SCHEMA_ID,\n version: candidate.version as typeof CRUD_SCHEMA_VERSION,\n id: candidate.id as string,\n kind: candidate.kind as 'crud',\n title: candidate.title as string,\n dataSource: candidate.dataSource as CrudPageSchema['dataSource'],\n search: candidate.search as FieldSchema[] | undefined,\n searchMode: candidate.searchMode as CrudPageSchema['searchMode'],\n form: candidate.form as FieldSchema[] | undefined,\n table: candidate.table as CrudPageSchema['table'],\n detail: candidate.detail as CrudPageSchema['detail'],\n toolbar: candidate.toolbar as PageActionSchema[] | undefined,\n meta: candidate.meta as CrudPageSchema['meta']\n }\n}\n\nfunction toRuntimeTabbedSchema(candidate: JsonRecord): TabbedPageSchema {\n return {\n $schema: candidate.$schema as typeof TABBED_PAGE_SCHEMA_ID,\n version: candidate.version as typeof TABBED_PAGE_SCHEMA_VERSION,\n id: candidate.id as string,\n kind: candidate.kind as 'tabs',\n tabs: candidate.tabs as TabbedPageSchema['tabs']\n }\n}\n\n/**\n * Server-safe development entry. It accepts unknown JSON from CLI/MCP before delegating to the\n * runtime validator, so untrusted candidates cannot trigger assumptions in typed runtime code.\n */\nexport function validateUnknownCrudPageSchema(candidate: unknown): SchemaValidationResult {\n const shapeDiagnostics = validateUnknownShape(candidate)\n if (shapeDiagnostics.length || !isRecord(candidate)) {\n return { valid: false, diagnostics: shapeDiagnostics }\n }\n return validateCrudPageSchema(toRuntimeSchema(candidate))\n}\n\n/** Validates every page schema the Runtime can render without importing React. */\nexport function validateUnknownPageSchema(candidate: unknown): SchemaValidationResult {\n if (!isRecord(candidate)) return validateUnknownCrudPageSchema(candidate)\n if (candidate.kind === 'crud' || candidate.$schema === CRUD_SCHEMA_ID) {\n return validateUnknownCrudPageSchema(candidate)\n }\n if (candidate.kind !== 'tabs' && candidate.$schema !== TABBED_PAGE_SCHEMA_ID)\n return validateUnknownCrudPageSchema(candidate)\n if (!Array.isArray(candidate.tabs) || !candidate.tabs.every(isRecord)) {\n return {\n valid: false,\n diagnostics: [diagnostic('/tabs', 'tabs.type', 'tabs \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4')]\n }\n }\n for (const [index, tab] of candidate.tabs.entries()) {\n const contentPath = `/tabs/${index}/content`\n if (!isRecord(tab.content)) {\n return {\n valid: false,\n diagnostics: [diagnostic(contentPath, 'tabs.content', 'tab content \u5FC5\u987B\u662F CRUD \u6216 Slot')]\n }\n }\n if (tab.content.type !== 'crud' && tab.content.type !== 'slot') {\n return {\n valid: false,\n diagnostics: [diagnostic(`${contentPath}/type`, 'tabs.content', 'tab content \u5FC5\u987B\u662F CRUD \u6216 Slot')]\n }\n }\n if (tab.content.type === 'crud' && !isRecord(tab.content.schema)) {\n return {\n valid: false,\n diagnostics: [diagnostic(`${contentPath}/schema`, 'tabs.content', 'CRUD tab \u5FC5\u987B\u63D0\u4F9B\u5BF9\u8C61 schema')]\n }\n }\n if (tab.content.type === 'crud') {\n const result = validateUnknownCrudPageSchema(tab.content.schema)\n if (!result.valid) {\n return {\n valid: false,\n diagnostics: result.diagnostics.map((item) => ({\n ...item,\n path: `${contentPath}/schema${item.path}`\n }))\n }\n }\n }\n }\n return validateTabbedPageSchema(toRuntimeTabbedSchema(candidate))\n}\n\n/** Serializable capabilities supplied by the current runtime without application Manifest entries. */\nexport function getBuiltinCapabilities(): string[] {\n return [...builtInCapabilities]\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { BestFieldComponent, BestFieldRule } from '../ui/types'\n\nexport const CRUD_SCHEMA_ID = 'https://best.dev/schema/crud/v1' as const\nexport const CRUD_SCHEMA_VERSION = 1 as const\nexport const TABBED_PAGE_SCHEMA_ID = 'https://best.dev/schema/tabs/v1' as const\nexport const TABBED_PAGE_SCHEMA_VERSION = 1 as const\n\nexport type Condition =\n | { operator: 'equals'; field: string; value: string | number | boolean | null }\n | { operator: 'notEmpty'; field: string }\n | { operator: 'modeEquals'; value: FormMode }\n | { operator: 'and' | 'or'; conditions: Condition[] }\n | { operator: 'not'; condition: Condition }\n\nexport type FormMode = 'create' | 'edit' | 'detail'\n\nexport type FieldSchema = {\n field: string\n label: string\n component: BestFieldComponent\n placeholder?: string\n dict?: string\n required?: boolean\n disabled?: boolean\n hidden?: boolean\n maxDate?: 'today'\n span?: number\n defaultValue?: string | number | boolean | null\n rules?: BestFieldRule[]\n /** Application-specific form control registered in the BestProvider registry. */\n slot?: string\n remoteService?: string\n searchField?: string\n labelField?: string\n valueField?: string\n debounceMs?: number\n pageSize?: number\n visibleWhen?: Condition\n disabledWhen?: Condition\n /** Clears stale dependent values when this field becomes hidden. */\n clearWhenHidden?: boolean\n /** Repeated object fields, for rules such as tiered pricing. */\n itemFields?: Omit<FieldSchema, 'itemFields'>[]\n minItems?: number\n maxItems?: number\n}\n\nexport type CompositeColumnItemSchema = {\n label?: string\n field: string\n dict?: string\n format?: 'date' | 'datetime' | 'money' | 'text'\n emptyText?: string\n}\n\nexport type CompositeColumnSchema = {\n layout?: 'vertical' | 'horizontal'\n gap?: number\n items: CompositeColumnItemSchema[]\n}\n\nexport type TableColumnSchema = {\n field?: string\n title: string\n dict?: string\n width?: number\n fixed?: 'left' | 'right'\n format?: 'date' | 'datetime' | 'money' | 'text'\n slot?: string\n composite?: CompositeColumnSchema\n}\n\nexport type TableExpandableSchema = {\n /** Nested row field name. Defaults to Ant Design Table's `children`. */\n childrenField?: string\n defaultExpandAllRows?: boolean\n defaultExpandedRowKeys?: (string | number)[]\n indentSize?: number\n}\n\nexport type TableRowSelectionSchema = {\n enabled?: boolean\n type?: 'checkbox' | 'radio'\n /** When false, selecting a parent also selects its descendants. */\n checkStrictly?: boolean\n preserveSelectedRowKeys?: boolean\n}\n\nexport type DetailFieldSchema = {\n field: string\n label: string\n dict?: string\n span?: number\n slot?: string\n format?: DetailFormat | DetailFormatConfig\n visibleWhen?: Condition\n emptyText?: string\n}\n\nexport type DetailFormat = 'text' | 'number' | 'money' | 'date' | 'datetime' | 'boolean' | 'json'\n\nexport type DetailFormatConfig = {\n type: DetailFormat\n emptyText?: string\n precision?: number\n timezone?: string\n}\n\nexport type DetailTableColumnSchema = {\n field: string\n title: string\n width?: number\n fixed?: 'left' | 'right'\n dict?: string\n format?: DetailFormat | DetailFormatConfig\n slot?: string\n}\n\nexport type DetailTableSchema = {\n data: string\n rowKey?: string\n columns: DetailTableColumnSchema[]\n scrollX?: number | string\n}\n\nexport type DetailSectionSchema = {\n key: string\n title?: string\n description?: string\n visibleWhen?: Condition\n layout?: 'fields' | 'table' | 'slot'\n columns?: number\n span?: number\n variant?: 'plain' | 'card'\n fields?: DetailFieldSchema[]\n table?: DetailTableSchema\n slot?: string\n}\n\nexport type PageActionButtonType = 'primary' | 'default' | 'link' | 'text' | 'dashed'\n\nexport type PageActionSchema = {\n id: string\n label: string\n effect: 'openCreate' | 'openDetail' | 'openEdit' | 'remove' | 'runAction' | 'slot' | 'closeDetail'\n action?: string\n slot?: string\n access?: string\n confirm?: string\n /** Visual button style; omitted actions use the runtime area default. */\n buttonType?: PageActionButtonType\n}\n\nexport type CrudPageSchema = {\n $schema: typeof CRUD_SCHEMA_ID\n version: typeof CRUD_SCHEMA_VERSION\n id: string\n kind: 'crud'\n title: string\n dataSource: {\n list: string\n detail?: string\n create?: string\n update?: string\n remove?: string\n }\n search?: FieldSchema[]\n searchMode?: 'proTable' | 'bestSearch'\n form?: FieldSchema[]\n table: {\n rowKey: string | string[]\n columns: TableColumnSchema[]\n actions?: PageActionSchema[]\n scrollX?: number\n pageSize?: number\n expandable?: TableExpandableSchema\n rowSelection?: TableRowSelectionSchema\n }\n detail?: {\n mode?: 'drawer' | 'modal' | 'inline'\n width?: number | string\n columns?: number\n gap?: number | string\n fields?: DetailFieldSchema[]\n sections?: DetailSectionSchema[]\n footer?: PageActionSchema[]\n }\n toolbar?: PageActionSchema[]\n meta?: {\n generatedBy?: string\n generatedAt?: string\n }\n}\n\nexport type TabContentSchema =\n | { type: 'crud'; schema: CrudPageSchema }\n | { type: 'slot'; slot: string }\n\nexport type TabSchema = {\n key: string\n label: string\n access?: string\n /** Defaults to true so inactive CRUD pages do not fetch until selected. */\n destroyOnHidden?: boolean\n content: TabContentSchema\n}\n\n/** A page composition schema with runtime-owned tab navigation. */\nexport type TabbedPageSchema = {\n $schema: typeof TABBED_PAGE_SCHEMA_ID\n version: typeof TABBED_PAGE_SCHEMA_VERSION\n id: string\n kind: 'tabs'\n tabs: TabSchema[]\n}\n", "import type { BestRegistry } from '../runtime'\nimport {\n type Condition,\n CRUD_SCHEMA_ID,\n CRUD_SCHEMA_VERSION,\n type CrudPageSchema,\n type FieldSchema,\n type PageActionSchema,\n TABBED_PAGE_SCHEMA_ID,\n TABBED_PAGE_SCHEMA_VERSION,\n type TabbedPageSchema\n} from './schema'\n\nexport type SchemaDiagnostic = {\n path: string\n code: string\n message: string\n}\n\nexport type SchemaValidationResult = {\n valid: boolean\n diagnostics: SchemaDiagnostic[]\n}\n\nconst fieldComponents = new Set([\n 'input',\n 'number',\n 'select',\n 'remoteSelect',\n 'date',\n 'dateRange',\n 'textarea',\n 'slot',\n 'repeatable'\n])\nconst builtInEffects = new Set([\n 'openCreate',\n 'openDetail',\n 'openEdit',\n 'remove',\n 'runAction',\n 'slot',\n 'closeDetail'\n])\nconst columnFormats = new Set(['date', 'datetime', 'money', 'text'])\nconst detailFormats = new Set(['text', 'number', 'money', 'date', 'datetime', 'boolean', 'json'])\n\nfunction push(diagnostics: SchemaDiagnostic[], path: string, code: string, message: string) {\n diagnostics.push({ path, code, message })\n}\n\nfunction validateCondition(condition: Condition, path: string, diagnostics: SchemaDiagnostic[]) {\n if (!condition || typeof condition !== 'object') {\n push(diagnostics, path, 'condition.type', '\u6761\u4EF6\u5FC5\u987B\u662F\u5BF9\u8C61')\n return\n }\n if (condition.operator === 'equals') {\n if (typeof condition.field !== 'string' || condition.field === '') {\n push(diagnostics, path, 'condition.field', 'equals \u6761\u4EF6\u5FC5\u987B\u6307\u5B9A\u5B57\u6BB5\u540D')\n }\n return\n }\n if (condition.operator === 'notEmpty') {\n if (typeof condition.field !== 'string' || condition.field === '') {\n push(diagnostics, path, 'condition.field', 'notEmpty \u6761\u4EF6\u5FC5\u987B\u6307\u5B9A\u5B57\u6BB5\u540D')\n }\n return\n }\n if (condition.operator === 'modeEquals') {\n return\n }\n if (\n (condition.operator === 'and' || condition.operator === 'or') &&\n !Array.isArray(condition.conditions)\n ) {\n push(diagnostics, path, 'condition.conditions', '\u7EC4\u5408\u6761\u4EF6\u5FC5\u987B\u6307\u5B9A conditions \u6570\u7EC4')\n return\n }\n if (condition.operator === 'and' || condition.operator === 'or') {\n if (condition.conditions.length === 0) {\n push(diagnostics, path, 'condition.empty', '\u7EC4\u5408\u6761\u4EF6\u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u5B50\u6761\u4EF6')\n }\n condition.conditions.forEach((item, index) => {\n validateCondition(item, `${path}/conditions/${index}`, diagnostics)\n })\n return\n }\n if (condition.operator === 'not') {\n if (!condition.condition) {\n push(diagnostics, path, 'condition.missing', 'not \u6761\u4EF6\u5FC5\u987B\u6307\u5B9A condition')\n return\n }\n validateCondition(condition.condition, `${path}/condition`, diagnostics)\n return\n }\n push(diagnostics, path, 'condition.operator', `\u4E0D\u652F\u6301\u7684\u6761\u4EF6\uFF1A${(condition as { operator?: unknown }).operator}`)\n}\n\nfunction validateDetailField(\n field: import('./schema').DetailFieldSchema,\n path: string,\n registry: BestRegistry | undefined,\n diagnostics: SchemaDiagnostic[]\n) {\n if (field.visibleWhen) validateCondition(field.visibleWhen, `${path}/visibleWhen`, diagnostics)\n if (field.slot && registry && !registry.slots[field.slot])\n push(diagnostics, `${path}/slot`, 'registry.slot', `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${field.slot}`)\n const format = typeof field.format === 'object' ? field.format.type : field.format\n if (format && !detailFormats.has(format))\n push(diagnostics, `${path}/format`, 'detail.format', `\u4E0D\u652F\u6301\u7684\u8BE6\u60C5\u683C\u5F0F\uFF1A${format}`)\n}\n\nfunction validateFields(\n fields: FieldSchema[] | undefined,\n path: string,\n registry: BestRegistry | undefined,\n diagnostics: SchemaDiagnostic[]\n) {\n const seen = new Set<string>()\n fields?.forEach((field, index) => {\n const fieldPath = `${path}/${index}`\n if (!field.field) push(diagnostics, fieldPath, 'field.missing', '\u5B57\u6BB5\u540D\u4E0D\u80FD\u4E3A\u7A7A')\n if (seen.has(field.field))\n push(diagnostics, fieldPath, 'field.duplicate', `\u5B57\u6BB5\u91CD\u590D\uFF1A${field.field}`)\n seen.add(field.field)\n if (!fieldComponents.has(field.component))\n push(diagnostics, fieldPath, 'field.component', `\u4E0D\u652F\u6301\u7684\u7EC4\u4EF6\uFF1A${field.component}`)\n if (field.dict && registry && !registry.dictionaries[field.dict]) {\n push(diagnostics, fieldPath, 'registry.dictionary', `\u672A\u6CE8\u518C\u5B57\u5178\uFF1A${field.dict}`)\n }\n if (field.component === 'remoteSelect' && !field.remoteService)\n push(diagnostics, fieldPath, 'field.remoteService', 'remoteSelect \u5FC5\u987B\u6307\u5B9A remoteService')\n if (field.remoteService && registry && !registry.services[field.remoteService])\n push(diagnostics, fieldPath, 'registry.service', `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${field.remoteService}`)\n if (field.component === 'slot' && !field.slot)\n push(diagnostics, fieldPath, 'field.slot', 'slot \u7EC4\u4EF6\u5FC5\u987B\u6307\u5B9A slot key')\n if (field.component === 'repeatable' && !field.itemFields?.length)\n push(\n diagnostics,\n fieldPath,\n 'field.repeatable',\n 'repeatable \u7EC4\u4EF6\u81F3\u5C11\u9700\u8981\u4E00\u4E2A itemFields \u5B57\u6BB5'\n )\n if (field.itemFields?.length)\n validateFields(\n field.itemFields as FieldSchema[],\n `${fieldPath}/itemFields`,\n registry,\n diagnostics\n )\n if (\n field.minItems !== undefined &&\n field.maxItems !== undefined &&\n field.minItems > field.maxItems\n )\n push(diagnostics, fieldPath, 'field.repeatable.range', 'minItems \u4E0D\u80FD\u5927\u4E8E maxItems')\n if (field.slot && registry && !registry.slots[field.slot])\n push(diagnostics, fieldPath, 'registry.slot', `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${field.slot}`)\n if (field.visibleWhen)\n validateCondition(field.visibleWhen, `${fieldPath}/visibleWhen`, diagnostics)\n if (field.disabledWhen)\n validateCondition(field.disabledWhen, `${fieldPath}/disabledWhen`, diagnostics)\n })\n}\n\nfunction validateActions(\n actions: PageActionSchema[] | undefined,\n path: string,\n registry: BestRegistry | undefined,\n hasRemoveService: boolean,\n diagnostics: SchemaDiagnostic[]\n) {\n actions?.forEach((action, index) => {\n const actionPath = `${path}/${index}`\n if (!action.id) push(diagnostics, actionPath, 'action.missing', '\u52A8\u4F5C id \u4E0D\u80FD\u4E3A\u7A7A')\n if (!builtInEffects.has(action.effect))\n push(diagnostics, actionPath, 'action.effect', `\u4E0D\u652F\u6301\u7684\u52A8\u4F5C\uFF1A${action.effect}`)\n if (action.effect === 'runAction' && !action.action)\n push(diagnostics, actionPath, 'action.key', 'runAction \u5FC5\u987B\u6307\u5B9A action key')\n if (action.effect === 'remove' && !hasRemoveService)\n push(diagnostics, actionPath, 'action.removeService', 'remove \u52A8\u4F5C\u5FC5\u987B\u914D\u7F6E dataSource.remove')\n if (action.effect === 'slot' && !action.slot)\n push(diagnostics, actionPath, 'action.slot', 'slot \u52A8\u4F5C\u5FC5\u987B\u6307\u5B9A slot key')\n if (action.action && registry && !registry.actions[action.action]) {\n push(diagnostics, actionPath, 'registry.action', `\u672A\u6CE8\u518C\u52A8\u4F5C\uFF1A${action.action}`)\n }\n if (action.slot && registry && !registry.slots[action.slot]) {\n push(diagnostics, actionPath, 'registry.slot', `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${action.slot}`)\n }\n })\n}\n\nexport function validateCrudPageSchema(\n schema: CrudPageSchema,\n registry?: BestRegistry\n): SchemaValidationResult {\n const diagnostics: SchemaDiagnostic[] = []\n if (schema.$schema !== CRUD_SCHEMA_ID)\n push(diagnostics, '/$schema', 'schema.id', `\u4EC5\u652F\u6301 ${CRUD_SCHEMA_ID}`)\n if (schema.version !== CRUD_SCHEMA_VERSION)\n push(diagnostics, '/version', 'schema.version', `\u4EC5\u652F\u6301\u7248\u672C ${CRUD_SCHEMA_VERSION}`)\n if (!schema.id) push(diagnostics, '/id', 'page.id', '\u9875\u9762 id \u4E0D\u80FD\u4E3A\u7A7A')\n if (!schema.title) push(diagnostics, '/title', 'page.title', '\u9875\u9762\u6807\u9898\u4E0D\u80FD\u4E3A\u7A7A')\n if (!schema.dataSource?.list)\n push(diagnostics, '/dataSource/list', 'service.list', '\u5217\u8868\u670D\u52A1\u4E0D\u80FD\u4E3A\u7A7A')\n if (schema.dataSource?.list && registry && !registry.listServices[schema.dataSource.list]) {\n push(\n diagnostics,\n '/dataSource/list',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.list}`\n )\n }\n if (schema.dataSource?.detail && registry && !registry.services[schema.dataSource.detail]) {\n push(\n diagnostics,\n '/dataSource/detail',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.detail}`\n )\n }\n if (schema.dataSource?.create && registry && !registry.services[schema.dataSource.create]) {\n push(\n diagnostics,\n '/dataSource/create',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.create}`\n )\n }\n if (schema.dataSource?.update && registry && !registry.services[schema.dataSource.update]) {\n push(\n diagnostics,\n '/dataSource/update',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.update}`\n )\n }\n if (schema.dataSource?.remove && registry && !registry.services[schema.dataSource.remove]) {\n push(\n diagnostics,\n '/dataSource/remove',\n 'registry.service',\n `\u672A\u6CE8\u518C\u670D\u52A1\uFF1A${schema.dataSource.remove}`\n )\n }\n validateFields(schema.search, '/search', registry, diagnostics)\n validateFields(schema.form, '/form', registry, diagnostics)\n if (!schema.table?.rowKey) push(diagnostics, '/table/rowKey', 'table.rowKey', 'rowKey \u4E0D\u80FD\u4E3A\u7A7A')\n if (!schema.table?.columns?.length)\n push(diagnostics, '/table/columns', 'table.columns', '\u81F3\u5C11\u9700\u8981\u4E00\u5217')\n schema.table?.columns?.forEach((column, index) => {\n if (!column.field && !column.composite) {\n push(\n diagnostics,\n `/table/columns/${index}`,\n 'column.field',\n '\u666E\u901A\u5217\u5FC5\u987B\u6307\u5B9A field\uFF0C\u7EC4\u5408\u5217\u5FC5\u987B\u6307\u5B9A composite'\n )\n }\n if (column.composite) {\n if (!column.composite.items?.length) {\n push(\n diagnostics,\n `/table/columns/${index}/composite/items`,\n 'column.composite.items',\n '\u7EC4\u5408\u5217\u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u5B57\u6BB5'\n )\n }\n column.composite.items?.forEach((item, itemIndex) => {\n if (!item.field) {\n push(\n diagnostics,\n `/table/columns/${index}/composite/items/${itemIndex}/field`,\n 'column.composite.field',\n '\u7EC4\u5408\u5217\u5B57\u6BB5\u4E0D\u80FD\u4E3A\u7A7A'\n )\n }\n if (item.format && !columnFormats.has(item.format)) {\n push(\n diagnostics,\n `/table/columns/${index}/composite/items/${itemIndex}/format`,\n 'column.composite.format',\n `\u4E0D\u652F\u6301\u7684\u683C\u5F0F\uFF1A${item.format}`\n )\n }\n if (item.dict && registry && !registry.dictionaries[item.dict]) {\n push(\n diagnostics,\n `/table/columns/${index}/composite/items/${itemIndex}/dict`,\n 'registry.dictionary',\n `\u672A\u6CE8\u518C\u5B57\u5178\uFF1A${item.dict}`\n )\n }\n })\n }\n if (column.fixed !== undefined && column.fixed !== 'left' && column.fixed !== 'right') {\n push(\n diagnostics,\n `/table/columns/${index}/fixed`,\n 'column.fixed',\n `\u4E0D\u652F\u6301\u7684\u56FA\u5B9A\u4F4D\u7F6E\uFF1A${column.fixed}`\n )\n }\n if (column.format && !columnFormats.has(column.format)) {\n push(\n diagnostics,\n `/table/columns/${index}/format`,\n 'column.format',\n `\u4E0D\u652F\u6301\u7684\u683C\u5F0F\uFF1A${column.format}`\n )\n }\n if (column.dict && registry && !registry.dictionaries[column.dict]) {\n push(\n diagnostics,\n `/table/columns/${index}/dict`,\n 'registry.dictionary',\n `\u672A\u6CE8\u518C\u5B57\u5178\uFF1A${column.dict}`\n )\n }\n if (column.slot && registry && !registry.slots[column.slot]) {\n push(\n diagnostics,\n `/table/columns/${index}/slot`,\n 'registry.slot',\n `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${column.slot}`\n )\n }\n })\n if (schema.detail !== undefined) {\n if (\n !schema.detail ||\n typeof schema.detail !== 'object' ||\n (schema.detail.fields !== undefined && !Array.isArray(schema.detail.fields)) ||\n (schema.detail.sections !== undefined && !Array.isArray(schema.detail.sections))\n ) {\n push(diagnostics, '/detail', 'detail.type', 'detail \u5FC5\u987B\u5305\u542B fields \u6216 sections \u6570\u7EC4')\n } else {\n schema.detail.fields?.forEach((field, index) => validateDetailField(field, `/detail/fields/${index}`, registry, diagnostics))\n schema.detail.sections?.forEach((section, index) => {\n if (section.visibleWhen) validateCondition(section.visibleWhen, `/detail/sections/${index}/visibleWhen`, diagnostics)\n if (!section.key) push(diagnostics, `/detail/sections/${index}/key`, 'detail.section.key', '\u8BE6\u60C5\u533A\u5757\u5FC5\u987B\u6307\u5B9A key')\n if (section.span !== undefined && (!Number.isInteger(section.span) || section.span < 1))\n push(diagnostics, `/detail/sections/${index}/span`, 'detail.section.span', '\u8BE6\u60C5\u533A\u5757 span \u5FC5\u987B\u662F\u6B63\u6574\u6570')\n if (section.columns !== undefined && (!Number.isInteger(section.columns) || section.columns < 1))\n push(diagnostics, `/detail/sections/${index}/columns`, 'detail.section.columns', '\u8BE6\u60C5\u5B57\u6BB5 columns \u5FC5\u987B\u662F\u6B63\u6574\u6570')\n if (section.layout === 'slot' && !section.slot)\n push(diagnostics, `/detail/sections/${index}/slot`, 'detail.slot', 'slot \u533A\u5757\u5FC5\u987B\u6307\u5B9A slot')\n if (section.layout === 'table' && !section.table)\n push(diagnostics, `/detail/sections/${index}/table`, 'detail.table', 'table \u533A\u5757\u5FC5\u987B\u6307\u5B9A table')\n if (section.table && typeof section.table.data !== 'string')\n push(diagnostics, `/detail/sections/${index}/table/data`, 'detail.table.data', '\u8BE6\u60C5\u8868\u683C data \u5FC5\u987B\u662F\u5B57\u6BB5\u8DEF\u5F84')\n if (section.slot && registry && !registry.slots[section.slot])\n push(diagnostics, `/detail/sections/${index}/slot`, 'registry.slot', `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${section.slot}`)\n section.fields?.forEach((field, fieldIndex) => validateDetailField(field, `/detail/sections/${index}/fields/${fieldIndex}`, registry, diagnostics))\n })\n }\n }\n validateActions(\n schema.table?.actions,\n '/table/actions',\n registry,\n Boolean(schema.dataSource?.remove),\n diagnostics\n )\n validateActions(\n schema.toolbar,\n '/toolbar',\n registry,\n Boolean(schema.dataSource?.remove),\n diagnostics\n )\n validateActions(\n schema.detail?.footer,\n '/detail/footer',\n registry,\n Boolean(schema.dataSource?.remove),\n diagnostics\n )\n return { valid: diagnostics.length === 0, diagnostics }\n}\n\nexport function assertValidCrudPageSchema(schema: CrudPageSchema, registry?: BestRegistry) {\n const result = validateCrudPageSchema(schema, registry)\n if (!result.valid) {\n const message = result.diagnostics.map((item) => `${item.path}: ${item.message}`).join('\\n')\n throw new Error(`Schema \u6821\u9A8C\u5931\u8D25\uFF1A\\n${message}`)\n }\n}\n\nexport function validateTabbedPageSchema(\n schema: TabbedPageSchema,\n registry?: BestRegistry\n): SchemaValidationResult {\n const diagnostics: SchemaDiagnostic[] = []\n if (schema.$schema !== TABBED_PAGE_SCHEMA_ID)\n push(diagnostics, '/$schema', 'schema.id', `\u4EC5\u652F\u6301 ${TABBED_PAGE_SCHEMA_ID}`)\n if (schema.version !== TABBED_PAGE_SCHEMA_VERSION)\n push(diagnostics, '/version', 'schema.version', `\u4EC5\u652F\u6301\u7248\u672C ${TABBED_PAGE_SCHEMA_VERSION}`)\n if (!schema.id) push(diagnostics, '/id', 'page.id', '\u9875\u9762 id \u4E0D\u80FD\u4E3A\u7A7A')\n if (!Array.isArray(schema.tabs) || schema.tabs.length === 0) {\n push(diagnostics, '/tabs', 'tabs.required', '\u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u9875\u7B7E')\n return { valid: false, diagnostics }\n }\n const keys = new Set<string>()\n schema.tabs.forEach((tab, index) => {\n const path = `/tabs/${index}`\n if (!tab.key) push(diagnostics, path, 'tab.key', '\u9875\u7B7E key \u4E0D\u80FD\u4E3A\u7A7A')\n if (keys.has(tab.key)) push(diagnostics, path, 'tab.duplicate', `\u9875\u7B7E key \u91CD\u590D\uFF1A${tab.key}`)\n keys.add(tab.key)\n if (!tab.label) push(diagnostics, path, 'tab.label', '\u9875\u7B7E\u6807\u9898\u4E0D\u80FD\u4E3A\u7A7A')\n if (tab.content.type === 'crud') {\n const result = validateCrudPageSchema(tab.content.schema, registry)\n diagnostics.push(...result.diagnostics.map((item) => ({ ...item, path: `${path}/content/schema${item.path}` })))\n } else if (tab.content.type === 'slot') {\n if (!tab.content.slot) push(diagnostics, path, 'tab.slot', 'slot \u9875\u7B7E\u5FC5\u987B\u6307\u5B9A slot key')\n if (tab.content.slot && registry && !registry.slots[tab.content.slot])\n push(diagnostics, path, 'registry.slot', `\u672A\u6CE8\u518C\u63D2\u69FD\uFF1A${tab.content.slot}`)\n } else {\n push(diagnostics, path, 'tab.content', '\u4E0D\u652F\u6301\u7684\u9875\u7B7E\u5185\u5BB9\u7C7B\u578B')\n }\n })\n return { valid: diagnostics.length === 0, diagnostics }\n}\n\nexport function assertValidTabbedPageSchema(schema: TabbedPageSchema, registry?: BestRegistry) {\n const result = validateTabbedPageSchema(schema, registry)\n if (!result.valid) {\n const message = result.diagnostics.map((item) => `${item.path}: ${item.message}`).join('\\n')\n throw new Error(`Schema \u6821\u9A8C\u5931\u8D25\uFF1A\\n${message}`)\n }\n}\n", "import {\n CRUD_SCHEMA_ID,\n TABBED_PAGE_SCHEMA_ID\n} from './schema'\nimport type {\n CRUD_SCHEMA_VERSION,\n CrudPageSchema,\n FieldSchema,\n PageActionSchema,\n TABBED_PAGE_SCHEMA_VERSION,\n TabbedPageSchema\n} from './schema'\nimport type { SchemaDiagnostic, SchemaValidationResult } from './validate'\nimport { validateCrudPageSchema, validateTabbedPageSchema } from './validate'\n\nconst builtInCapabilities = [\n 'builtin.effect.openCreate',\n 'builtin.effect.openDetail',\n 'builtin.effect.openEdit',\n 'builtin.effect.remove',\n 'builtin.effect.runAction',\n 'builtin.effect.slot',\n 'builtin.effect.closeDetail',\n 'builtin.format.date',\n 'builtin.format.datetime',\n 'builtin.format.money',\n 'builtin.format.text',\n 'builtin.field.input',\n 'builtin.field.number',\n 'builtin.field.select',\n 'builtin.field.remoteSelect',\n 'builtin.field.date',\n 'builtin.field.dateRange',\n 'builtin.field.textarea',\n 'builtin.field.slot',\n 'builtin.field.repeatable'\n] as const\n\ntype JsonRecord = Record<string, unknown>\n\nfunction isRecord(value: unknown): value is JsonRecord {\n return !!value && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction arrayOfRecords(value: unknown): JsonRecord[] | undefined {\n return Array.isArray(value) && value.every(isRecord) ? value : undefined\n}\n\nfunction diagnostic(path: string, code: string, message: string): SchemaDiagnostic {\n return { path, code, message }\n}\n\nfunction validateUnknownShape(candidate: unknown): SchemaDiagnostic[] {\n if (!isRecord(candidate)) return [diagnostic('', 'schema.type', 'Schema \u5FC5\u987B\u662F JSON \u5BF9\u8C61')]\n const diagnostics: SchemaDiagnostic[] = []\n if (!isRecord(candidate.dataSource))\n diagnostics.push(diagnostic('/dataSource', 'dataSource.type', 'dataSource \u5FC5\u987B\u662F\u5BF9\u8C61'))\n if (!isRecord(candidate.table))\n diagnostics.push(diagnostic('/table', 'table.type', 'table \u5FC5\u987B\u662F\u5BF9\u8C61'))\n for (const key of ['search', 'form'] as const) {\n if (candidate[key] !== undefined && !arrayOfRecords(candidate[key])) {\n diagnostics.push(diagnostic(`/${key}`, 'field.list', `${key} \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4`))\n }\n }\n if (isRecord(candidate.table)) {\n if (!arrayOfRecords(candidate.table.columns)) {\n diagnostics.push(diagnostic('/table/columns', 'column.list', 'columns \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4'))\n }\n if (candidate.table.actions !== undefined && !arrayOfRecords(candidate.table.actions)) {\n diagnostics.push(diagnostic('/table/actions', 'action.list', 'actions \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4'))\n }\n }\n if (candidate.toolbar !== undefined && !arrayOfRecords(candidate.toolbar)) {\n diagnostics.push(diagnostic('/toolbar', 'action.list', 'toolbar \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4'))\n }\n return diagnostics\n}\n\nfunction toRuntimeSchema(candidate: JsonRecord): CrudPageSchema {\n return {\n $schema: candidate.$schema as typeof CRUD_SCHEMA_ID,\n version: candidate.version as typeof CRUD_SCHEMA_VERSION,\n id: candidate.id as string,\n kind: candidate.kind as 'crud',\n title: candidate.title as string,\n dataSource: candidate.dataSource as CrudPageSchema['dataSource'],\n search: candidate.search as FieldSchema[] | undefined,\n searchMode: candidate.searchMode as CrudPageSchema['searchMode'],\n form: candidate.form as FieldSchema[] | undefined,\n table: candidate.table as CrudPageSchema['table'],\n detail: candidate.detail as CrudPageSchema['detail'],\n toolbar: candidate.toolbar as PageActionSchema[] | undefined,\n meta: candidate.meta as CrudPageSchema['meta']\n }\n}\n\nfunction toRuntimeTabbedSchema(candidate: JsonRecord): TabbedPageSchema {\n return {\n $schema: candidate.$schema as typeof TABBED_PAGE_SCHEMA_ID,\n version: candidate.version as typeof TABBED_PAGE_SCHEMA_VERSION,\n id: candidate.id as string,\n kind: candidate.kind as 'tabs',\n tabs: candidate.tabs as TabbedPageSchema['tabs']\n }\n}\n\n/**\n * Server-safe development entry. It accepts unknown JSON from CLI/MCP before delegating to the\n * runtime validator, so untrusted candidates cannot trigger assumptions in typed runtime code.\n */\nexport function validateUnknownCrudPageSchema(candidate: unknown): SchemaValidationResult {\n const shapeDiagnostics = validateUnknownShape(candidate)\n if (shapeDiagnostics.length || !isRecord(candidate)) {\n return { valid: false, diagnostics: shapeDiagnostics }\n }\n return validateCrudPageSchema(toRuntimeSchema(candidate))\n}\n\n/** Validates every page schema the Runtime can render without importing React. */\nexport function validateUnknownPageSchema(candidate: unknown): SchemaValidationResult {\n if (!isRecord(candidate)) return validateUnknownCrudPageSchema(candidate)\n if (candidate.kind === 'crud' || candidate.$schema === CRUD_SCHEMA_ID) {\n return validateUnknownCrudPageSchema(candidate)\n }\n if (candidate.kind !== 'tabs' && candidate.$schema !== TABBED_PAGE_SCHEMA_ID)\n return validateUnknownCrudPageSchema(candidate)\n if (!Array.isArray(candidate.tabs) || !candidate.tabs.every(isRecord)) {\n return {\n valid: false,\n diagnostics: [diagnostic('/tabs', 'tabs.type', 'tabs \u5FC5\u987B\u662F\u5BF9\u8C61\u6570\u7EC4')]\n }\n }\n for (const [index, tab] of candidate.tabs.entries()) {\n const contentPath = `/tabs/${index}/content`\n if (!isRecord(tab.content)) {\n return {\n valid: false,\n diagnostics: [diagnostic(contentPath, 'tabs.content', 'tab content \u5FC5\u987B\u662F CRUD \u6216 Slot')]\n }\n }\n if (tab.content.type !== 'crud' && tab.content.type !== 'slot') {\n return {\n valid: false,\n diagnostics: [diagnostic(`${contentPath}/type`, 'tabs.content', 'tab content \u5FC5\u987B\u662F CRUD \u6216 Slot')]\n }\n }\n if (tab.content.type === 'crud' && !isRecord(tab.content.schema)) {\n return {\n valid: false,\n diagnostics: [diagnostic(`${contentPath}/schema`, 'tabs.content', 'CRUD tab \u5FC5\u987B\u63D0\u4F9B\u5BF9\u8C61 schema')]\n }\n }\n if (tab.content.type === 'crud') {\n const result = validateUnknownCrudPageSchema(tab.content.schema)\n if (!result.valid) {\n return {\n valid: false,\n diagnostics: result.diagnostics.map((item) => ({\n ...item,\n path: `${contentPath}/schema${item.path}`\n }))\n }\n }\n }\n }\n return validateTabbedPageSchema(toRuntimeTabbedSchema(candidate))\n}\n\n/** Serializable capabilities supplied by the current runtime without application Manifest entries. */\nexport function getBuiltinCapabilities(): string[] {\n return [...builtInCapabilities]\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/index.js CHANGED
@@ -1473,6 +1473,50 @@ function validateCrudPageSchema(schema, registry) {
1473
1473
  if (!schema.table?.columns?.length)
1474
1474
  push(diagnostics, "/table/columns", "table.columns", "\u81F3\u5C11\u9700\u8981\u4E00\u5217");
1475
1475
  schema.table?.columns?.forEach((column, index) => {
1476
+ if (!column.field && !column.composite) {
1477
+ push(
1478
+ diagnostics,
1479
+ `/table/columns/${index}`,
1480
+ "column.field",
1481
+ "\u666E\u901A\u5217\u5FC5\u987B\u6307\u5B9A field\uFF0C\u7EC4\u5408\u5217\u5FC5\u987B\u6307\u5B9A composite"
1482
+ );
1483
+ }
1484
+ if (column.composite) {
1485
+ if (!column.composite.items?.length) {
1486
+ push(
1487
+ diagnostics,
1488
+ `/table/columns/${index}/composite/items`,
1489
+ "column.composite.items",
1490
+ "\u7EC4\u5408\u5217\u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u5B57\u6BB5"
1491
+ );
1492
+ }
1493
+ column.composite.items?.forEach((item, itemIndex) => {
1494
+ if (!item.field) {
1495
+ push(
1496
+ diagnostics,
1497
+ `/table/columns/${index}/composite/items/${itemIndex}/field`,
1498
+ "column.composite.field",
1499
+ "\u7EC4\u5408\u5217\u5B57\u6BB5\u4E0D\u80FD\u4E3A\u7A7A"
1500
+ );
1501
+ }
1502
+ if (item.format && !columnFormats.has(item.format)) {
1503
+ push(
1504
+ diagnostics,
1505
+ `/table/columns/${index}/composite/items/${itemIndex}/format`,
1506
+ "column.composite.format",
1507
+ `\u4E0D\u652F\u6301\u7684\u683C\u5F0F\uFF1A${item.format}`
1508
+ );
1509
+ }
1510
+ if (item.dict && registry && !registry.dictionaries[item.dict]) {
1511
+ push(
1512
+ diagnostics,
1513
+ `/table/columns/${index}/composite/items/${itemIndex}/dict`,
1514
+ "registry.dictionary",
1515
+ `\u672A\u6CE8\u518C\u5B57\u5178\uFF1A${item.dict}`
1516
+ );
1517
+ }
1518
+ });
1519
+ }
1476
1520
  if (column.fixed !== void 0 && column.fixed !== "left" && column.fixed !== "right") {
1477
1521
  push(
1478
1522
  diagnostics,
@@ -1730,6 +1774,7 @@ function toDetailSection(section, record, dictionaries, slots) {
1730
1774
  }
1731
1775
  function toTableColumn(column, dictionary, slots) {
1732
1776
  const slot = column.slot;
1777
+ const composite = column.composite;
1733
1778
  const valueEnum = column.dict ? Object.fromEntries(
1734
1779
  (dictionary[column.dict] ?? []).map((item) => [String(item.value), { text: item.label }])
1735
1780
  ) : void 0;
@@ -1741,10 +1786,16 @@ function toTableColumn(column, dictionary, slots) {
1741
1786
  fixed: column.fixed,
1742
1787
  valueEnum,
1743
1788
  renderText: column.format && !slot && !column.dict ? (value) => formatCrudValue(value, column.format) : void 0,
1744
- render: slot ? (_value, record) => slots[slot]?.({
1789
+ render: composite ? (_value, record) => /* @__PURE__ */ jsx11("div", { style: { display: "flex", flexDirection: composite.layout === "horizontal" ? "row" : "column", gap: composite.gap ?? 2 }, children: composite.items.map((item) => {
1790
+ const rawValue = getPathValue3(record, item.field);
1791
+ const dictionaryItem = item.dict ? (dictionary[item.dict] ?? []).find((candidate) => String(candidate.value) === String(rawValue)) : void 0;
1792
+ const value = dictionaryItem?.label ?? formatCrudValue(rawValue, item.format);
1793
+ const content = rawValue == null || rawValue === "" ? item.emptyText ?? "-" : value;
1794
+ return /* @__PURE__ */ jsx11("div", { children: item.label ? `${item.label}\uFF1A${content}` : content }, item.field);
1795
+ }) }) : slot ? (_value, record) => slots[slot]?.({
1745
1796
  field: column.field,
1746
1797
  record,
1747
- value: record[column.field]
1798
+ value: column.field ? record[column.field] : void 0
1748
1799
  }) ?? "-" : void 0
1749
1800
  };
1750
1801
  }
@@ -1934,6 +1985,7 @@ function BestCrudPage({ adapter, className, schema }) {
1934
1985
  );
1935
1986
  const configuredColumns = schema.table.columns.map((column) => {
1936
1987
  const tableColumn = toTableColumn(column, registry.dictionaries, registry.slots);
1988
+ if (!column.field) return tableColumn;
1937
1989
  const searchColumn = searchColumns.get(column.field);
1938
1990
  if (!searchColumn) return tableColumn;
1939
1991
  searchColumns.delete(column.field);
@@ -1967,12 +2019,16 @@ function BestCrudPage({ adapter, className, schema }) {
1967
2019
  [listService, schema.title]
1968
2020
  );
1969
2021
  const rowKey = schema.table.rowKey;
2022
+ const [selectedRowKeys, setSelectedRowKeys] = useState4([]);
1970
2023
  const request = useCallback2(
1971
2024
  (params, sort) => pageRequest.request(
1972
2025
  toBestListQuery({ ...params, ...useBestSearch ? queryRef.current : {} }, sort)
1973
2026
  ),
1974
2027
  [pageRequest, useBestSearch]
1975
2028
  );
2029
+ useEffect3(() => {
2030
+ setSelectedRowKeys([]);
2031
+ }, [schema.id]);
1976
2032
  useLayoutEffect(() => {
1977
2033
  const previous = queryStateRef.current;
1978
2034
  if (previous.schemaId === schema.id && previous.searchSchemaSignature === searchSchemaSignature)
@@ -2060,6 +2116,19 @@ function BestCrudPage({ adapter, className, schema }) {
2060
2116
  pagination: { showSizeChanger: true, defaultPageSize: schema.table.pageSize ?? 20 },
2061
2117
  request,
2062
2118
  rowKey: Array.isArray(rowKey) ? (record) => rowKey.map((field) => String(record[field] ?? "")).join("-") : rowKey,
2119
+ expandable: schema.table.expandable ? {
2120
+ childrenColumnName: schema.table.expandable.childrenField ?? "children",
2121
+ defaultExpandAllRows: schema.table.expandable.defaultExpandAllRows,
2122
+ defaultExpandedRowKeys: schema.table.expandable.defaultExpandedRowKeys,
2123
+ indentSize: schema.table.expandable.indentSize
2124
+ } : void 0,
2125
+ rowSelection: schema.table.rowSelection?.enabled ? {
2126
+ type: schema.table.rowSelection.type ?? "checkbox",
2127
+ checkStrictly: schema.table.rowSelection.checkStrictly ?? true,
2128
+ preserveSelectedRowKeys: schema.table.rowSelection.preserveSelectedRowKeys,
2129
+ selectedRowKeys,
2130
+ onChange: (keys) => setSelectedRowKeys(keys)
2131
+ } : void 0,
2063
2132
  search: useBestSearch ? false : void 0,
2064
2133
  scroll: schema.table.scrollX ? { x: schema.table.scrollX } : void 0,
2065
2134
  toolBarRender: () => schema.toolbar?.map((action) => /* @__PURE__ */ jsx11(ActionButton, { action, onExecute: handleAction }, action.id)) ?? []