openxiangda 2.0.0-alpha.80 → 2.0.0-alpha.81

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.
Files changed (30) hide show
  1. package/dist/browser/components/resource/GeneratedResourceCrud.d.ts.map +1 -1
  2. package/dist/browser/components/resource/GeneratedResourceCrud.js +246 -20
  3. package/dist/browser/components/resource/GeneratedResourceCrud.js.map +1 -1
  4. package/dist/browser/components/resource/ResourceBatchActions.d.ts +9 -0
  5. package/dist/browser/components/resource/ResourceBatchActions.d.ts.map +1 -1
  6. package/dist/browser/components/resource/ResourceBatchActions.js +115 -1
  7. package/dist/browser/components/resource/ResourceBatchActions.js.map +1 -1
  8. package/dist/browser/components/resource/StandardResourcePages.d.ts +2 -5
  9. package/dist/browser/components/resource/StandardResourcePages.d.ts.map +1 -1
  10. package/dist/browser/components/resource/StandardResourcePages.js +5 -10
  11. package/dist/browser/components/resource/StandardResourcePages.js.map +1 -1
  12. package/dist/browser/components/resource/SurfaceFields.d.ts.map +1 -1
  13. package/dist/browser/components/resource/SurfaceFields.js +1 -6
  14. package/dist/browser/components/resource/SurfaceFields.js.map +1 -1
  15. package/dist/browser/components/resource/workflow-resource-import.d.ts +27 -0
  16. package/dist/browser/components/resource/workflow-resource-import.d.ts.map +1 -0
  17. package/dist/browser/components/resource/workflow-resource-import.js +35 -0
  18. package/dist/browser/components/resource/workflow-resource-import.js.map +1 -0
  19. package/dist/browser/components/workflow/StandardWorkflowPages.d.ts.map +1 -1
  20. package/dist/browser/components/workflow/StandardWorkflowPages.js +47 -24
  21. package/dist/browser/components/workflow/StandardWorkflowPages.js.map +1 -1
  22. package/dist/browser/platform-client.d.ts +21 -0
  23. package/dist/browser/platform-client.d.ts.map +1 -1
  24. package/dist/browser/platform-client.js +15 -0
  25. package/dist/browser/platform-client.js.map +1 -1
  26. package/dist/browser/styles.css +45 -14
  27. package/package.json +7 -7
  28. package/skills/openxiangda-v2/SKILL.md +3 -3
  29. package/skills/openxiangda-v2/references/data-authz.md +7 -2
  30. package/skills/openxiangda-v2/references/workspace.md +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"GeneratedResourceCrud.d.ts","sourceRoot":"","sources":["../../../../src/browser/components/resource/GeneratedResourceCrud.tsx"],"names":[],"mappings":"AAuFA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AASnF,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAsQD,wBAAgB,qBAAqB,CAAC,EACpC,YAAY,EACZ,IAAa,EACb,OAAmB,EACnB,UAAU,EAAE,kBAAkB,EAC9B,KAAK,GACN,EAAE;IACD,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC7C,OAAO,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC/B,UAAU,CAAC,EAAE,2BAA2B,CAAC;IACzC,KAAK,EAAE,2BAA2B,CAAC;CACpC,2CAqBA"}
1
+ {"version":3,"file":"GeneratedResourceCrud.d.ts","sourceRoot":"","sources":["../../../../src/browser/components/resource/GeneratedResourceCrud.tsx"],"names":[],"mappings":"AAgGA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AAWnF,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AA4QD,wBAAgB,qBAAqB,CAAC,EACpC,YAAY,EACZ,IAAa,EACb,OAAmB,EACnB,UAAU,EAAE,kBAAkB,EAC9B,KAAK,GACN,EAAE;IACD,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC7C,OAAO,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC/B,UAAU,CAAC,EAAE,2BAA2B,CAAC;IACzC,KAAK,EAAE,2BAA2B,CAAC;CACpC,2CAqBA"}
@@ -1,20 +1,20 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { ArrowRightOutlined, ColumnHeightOutlined, DeleteOutlined, EditOutlined, EyeOutlined, ExportOutlined, FilterOutlined, PlusOutlined, ReloadOutlined, SearchOutlined, SettingOutlined, } from '@ant-design/icons';
2
+ import { ArrowRightOutlined, ColumnHeightOutlined, DeleteOutlined, EditOutlined, EyeOutlined, ExportOutlined, FilterOutlined, PlusOutlined, ReloadOutlined, SaveOutlined, SearchOutlined, SettingOutlined, UndoOutlined, } from '@ant-design/icons';
3
3
  import { useCreate, useDelete, useList, useOne, useUpdate } from '@refinedev/core';
4
4
  import { App, Alert, Button, Card, Collapse, Descriptions, Dropdown, Empty, Form, Input, Modal, Popconfirm, Result, Space, Spin, Table, Tag, Tooltip, Typography, } from 'antd';
5
5
  import { Fragment, useEffect, useMemo, useState } from 'react';
6
6
  import { useNavigate, useParams } from 'react-router-dom';
7
7
  import { MobileResourceDetailPage, MobileResourceFormPage, MobileResourceListPage, ResourceDetailPage, ResourceFormPage, ResourceListPage, } from './StandardResourcePages';
8
8
  import { auditActorLabel, auditFieldChange, auditFieldCodes, listSurfaceFields, MobileSurfaceFieldControl, SurfaceAuditFieldValue, SurfaceFieldControl, SurfaceFieldValue, SurfaceFilterControl, } from './SurfaceFields';
9
- import { createNativeResourceClient, transactNativeData, } from '../../platform-client';
9
+ import { createNativeResourceClient, loadResourceListPreference, resetResourceListPreference, saveResourceListPreference, transactNativeData, } from '../../platform-client';
10
10
  import { normalizeFormValues, normalizeRecordForForm } from '../platform-fields/field-form-codec';
11
- import { DirectoryIdentityText } from '../../AuthoritativeSelector';
12
11
  import { useRuntime } from '../../runtime';
13
- import { ResourceBatchActions, ResourceImportButton } from './ResourceBatchActions';
12
+ import { ResourceBatchActions, ResourceImportButton, WorkflowResourceImportButton, } from './ResourceBatchActions';
14
13
  import { isAdminContributionAllowed, useAdminResourceContributions, } from '../../admin-contributions';
15
14
  import { SubtableField, SubtableValueDisplay, } from '../platform-fields/SubtableField';
16
15
  import { buildSubtableOperations, } from '../platform-fields/subtable-value';
17
16
  import { useResourceDefinitions } from '../../resource-definitions';
17
+ import { useWorkflowDefinitions } from '../../workflow-definitions';
18
18
  function resourceRecordPath(path, id) {
19
19
  if (!path || !path.includes(':id')) {
20
20
  throw new Error('OPENXIANGDA_GENERATED_RESOURCE_ROUTE_MISSING');
@@ -145,7 +145,12 @@ async function exportResourceRows(code, name, surface, fields, query, sort) {
145
145
  }
146
146
  function AuditEntry({ entry, resourceCode, surface, readable, }) {
147
147
  const fields = auditChangeFields(entry, surface).filter(readable);
148
- return (_jsxs("div", { className: "oxa-audit-entry", children: [_jsxs("div", { className: "oxa-audit-heading", children: [_jsx("strong", { children: auditOperationLabel(entry.operation) }), _jsxs(Typography.Text, { type: "secondary", children: ["\u7248\u672C ", entry.revision] })] }), _jsxs("div", { className: "oxa-audit-meta", children: [_jsx("span", { children: "\u64CD\u4F5C\u4EBA" }), entry.actor.principalType === 'user' || entry.actor.principalType === 'developer' ? (_jsx(DirectoryIdentityText, { id: entry.actor.subjectId, source: "user" })) : (_jsxs(Typography.Text, { children: [auditActorLabel(entry), "\uFF08", entry.actor.subjectId, "\uFF09"] })), _jsx("span", { children: "\u65F6\u95F4" }), _jsx(Typography.Text, { children: new Date(entry.occurredAt).toLocaleString('zh-CN') })] }), fields.length ? (_jsx("div", { className: "oxa-audit-changes", children: fields.map((field) => {
148
+ const actorName = entry.actorDisplay?.displayName || auditActorLabel(entry);
149
+ const occurredAt = new Date(entry.occurredAt).toLocaleString('zh-CN');
150
+ if (entry.operation === 'created') {
151
+ return (_jsx("div", { className: "oxa-audit-entry oxa-audit-entry-created", children: _jsxs(Typography.Text, { children: [_jsx("strong", { children: actorName }), " \u4E8E ", occurredAt, " \u521B\u5EFA\u8BB0\u5F55"] }) }));
152
+ }
153
+ return (_jsxs("div", { className: "oxa-audit-entry", children: [_jsxs("div", { className: "oxa-audit-heading", children: [_jsx("strong", { children: auditOperationLabel(entry.operation) }), _jsxs(Typography.Text, { type: "secondary", children: ["\u7248\u672C ", entry.revision] })] }), _jsxs("div", { className: "oxa-audit-meta", children: [_jsx("span", { children: "\u64CD\u4F5C\u4EBA" }), _jsx(Typography.Text, { children: actorName }), _jsx("span", { children: "\u65F6\u95F4" }), _jsx(Typography.Text, { children: occurredAt })] }), fields.length ? (_jsx("div", { className: "oxa-audit-changes", children: fields.map((field) => {
149
154
  const change = auditFieldChange(entry, field.key);
150
155
  const before = change?.before;
151
156
  const after = change?.after;
@@ -228,6 +233,7 @@ function GeneratedDesktopList({ definition, paths }) {
228
233
  const { hasCapability, hasReadCapability, identity } = useRuntime();
229
234
  const { code, name, surface, capabilities } = definition;
230
235
  const generated = surface.generated;
236
+ const workflowDefinitions = useWorkflowDefinitions();
231
237
  const contributions = useAdminResourceContributions(code);
232
238
  const fields = listSurfaceFields(surface.fields).filter((field) => fieldReadable(field, hasReadCapability, identity.isAppSuperAdmin));
233
239
  const readableFieldCodes = new Set(Object.entries(surface.fields)
@@ -238,12 +244,24 @@ function GeneratedDesktopList({ definition, paths }) {
238
244
  const [moreFiltersOpen, setMoreFiltersOpen] = useState(false);
239
245
  const [moreFilterDraft, setMoreFilterDraft] = useState({});
240
246
  const [density, setDensity] = useState('middle');
241
- const [visibleColumnKeys, setVisibleColumnKeys] = useState(() => fields.map((field) => field.key));
247
+ const [visibleColumnKeys, setVisibleColumnKeys] = useState(() => [
248
+ ...fields.map((field) => field.key),
249
+ 'created_at',
250
+ 'updated_at',
251
+ ]);
242
252
  const [selectedRowKeys, setSelectedRowKeys] = useState([]);
253
+ const [preferenceReady, setPreferenceReady] = useState(false);
254
+ const [preferenceSaving, setPreferenceSaving] = useState(false);
255
+ const [savedPreferenceFingerprint, setSavedPreferenceFingerprint] = useState('');
256
+ const [hasSavedPreference, setHasSavedPreference] = useState(false);
243
257
  const remove = useDelete();
244
258
  const rows = (state.list.result.data || []);
245
259
  useEffect(() => {
246
- setVisibleColumnKeys(fields.map((field) => field.key));
260
+ setVisibleColumnKeys([
261
+ ...fields.map((field) => field.key),
262
+ 'created_at',
263
+ 'updated_at',
264
+ ]);
247
265
  setMoreFiltersOpen(false);
248
266
  setMoreFilterDraft({});
249
267
  setDensity('middle');
@@ -256,12 +274,158 @@ function GeneratedDesktopList({ definition, paths }) {
256
274
  const importWritableFieldCodes = formFields
257
275
  .filter((field) => field.widget !== 'readonly' && fieldWritable(field, 'create', hasCapability, identity.isAppSuperAdmin))
258
276
  .map((field) => field.key);
277
+ const standardWorkflows = [...workflowDefinitions.values()].filter(workflow => workflow.subject.resourceCode === code &&
278
+ ['standalone', 'hidden-handoff'].includes(workflow.launch.mode) &&
279
+ Boolean(workflow.processOperationCode));
280
+ const standardWorkflow = surface.mutationOwner === 'workflow' && standardWorkflows.length === 1
281
+ ? standardWorkflows[0]
282
+ : undefined;
283
+ const workflowImportFieldCodes = formFields
284
+ .filter(field => !field.system &&
285
+ field.widget !== 'readonly' &&
286
+ field.type !== 'subtable')
287
+ .map(field => field.key);
259
288
  const batchWritableFields = formFields.filter((field) => !['file', 'readonly'].includes(field.widget || '') && fieldWritable(field, 'edit', hasCapability, identity.isAppSuperAdmin));
260
289
  const selectedRows = rows.filter((row) => selectedRowKeys.includes(row.id));
261
290
  const toolbarContributions = (contributions?.toolbar || []).filter((item) => isAdminContributionAllowed(item, hasCapability));
262
291
  const rowContributions = (contributions?.row || []).filter((item) => isAdminContributionAllowed(item, hasCapability));
263
292
  const canBatch = (generated.update && hasCapability(capabilities.update)) ||
264
293
  (generated.delete && hasCapability(capabilities.delete));
294
+ const configurableColumns = [
295
+ ...fields.map(field => ({ key: field.key, label: field.label })),
296
+ { key: 'created_at', label: '创建时间' },
297
+ { key: 'updated_at', label: '更新时间' },
298
+ ];
299
+ const listKey = `openxiangda-v2:resource:${code}`;
300
+ const preferencePayload = () => ({
301
+ version: 1,
302
+ columns: configurableColumns.map(column => ({
303
+ key: column.key,
304
+ visible: visibleColumnKeys.includes(column.key),
305
+ })),
306
+ filters: {
307
+ ...(state.query.keyword?.trim()
308
+ ? { keyword: state.query.keyword.trim() }
309
+ : {}),
310
+ ...(state.query.filters && Object.keys(state.query.filters).length
311
+ ? { values: state.query.filters }
312
+ : {}),
313
+ },
314
+ sorts: [
315
+ {
316
+ field: state.sort.field,
317
+ direction: state.sort.order === 'asc' ? 'ascend' : 'descend',
318
+ },
319
+ ],
320
+ density,
321
+ pageSize: state.pageSize,
322
+ });
323
+ const preferenceFingerprint = (preference) => JSON.stringify({
324
+ version: preference.version,
325
+ columns: preference.columns,
326
+ filters: preference.filters,
327
+ sorts: preference.sorts,
328
+ density: preference.density,
329
+ pageSize: preference.pageSize,
330
+ });
331
+ const currentPreferenceFingerprint = preferenceFingerprint(preferencePayload());
332
+ const preferenceDirty = preferenceReady &&
333
+ currentPreferenceFingerprint !== savedPreferenceFingerprint;
334
+ useEffect(() => {
335
+ let active = true;
336
+ setPreferenceReady(false);
337
+ const defaults = preferencePayload();
338
+ void loadResourceListPreference(listKey)
339
+ .then(preference => {
340
+ if (!active)
341
+ return;
342
+ const allowedColumns = new Set(configurableColumns.map(column => column.key));
343
+ const storedColumns = Array.isArray(preference?.columns)
344
+ ? preference.columns.filter(column => allowedColumns.has(column.key))
345
+ : [];
346
+ const visible = storedColumns
347
+ .filter(column => column.visible)
348
+ .map(column => column.key);
349
+ const nextVisible = visible.length
350
+ ? visible
351
+ : defaults.columns.filter(column => column.visible).map(column => column.key);
352
+ const allowedFilters = new Set(surface.list?.filterFields || []);
353
+ const filterValues = preference?.filters?.values &&
354
+ typeof preference.filters.values === 'object' &&
355
+ !Array.isArray(preference.filters.values)
356
+ ? Object.fromEntries(Object.entries(preference.filters.values).filter(([key]) => allowedFilters.has(key)))
357
+ : {};
358
+ const keyword = (surface.list?.searchableFields || []).length &&
359
+ typeof preference?.filters?.keyword === 'string'
360
+ ? preference.filters.keyword
361
+ : undefined;
362
+ const storedSort = preference?.sorts?.[0];
363
+ const sortableFields = new Set(fields.filter(field => field.sortable).map(field => field.key));
364
+ const nextSort = storedSort && sortableFields.has(storedSort.field)
365
+ ? {
366
+ field: storedSort.field,
367
+ order: storedSort.direction === 'descend' ? 'desc' : 'asc',
368
+ }
369
+ : defaults.sorts[0]
370
+ ? {
371
+ field: defaults.sorts[0].field,
372
+ order: defaults.sorts[0].direction === 'descend' ? 'desc' : 'asc',
373
+ }
374
+ : state.sort;
375
+ const nextDensity = ['small', 'middle', 'large'].includes(String(preference?.density || ''))
376
+ ? preference.density
377
+ : defaults.density;
378
+ const nextPageSize = Number.isSafeInteger(preference?.pageSize) &&
379
+ Number(preference?.pageSize) >= 10 &&
380
+ Number(preference?.pageSize) <= 100
381
+ ? Number(preference.pageSize)
382
+ : defaults.pageSize;
383
+ const nextQuery = {
384
+ ...(keyword ? { keyword } : {}),
385
+ ...(Object.keys(filterValues).length ? { filters: filterValues } : {}),
386
+ };
387
+ setVisibleColumnKeys(nextVisible);
388
+ setDensity(nextDensity);
389
+ state.setDraft(nextQuery);
390
+ state.setQuery(nextQuery);
391
+ state.setSort(nextSort);
392
+ state.setPageSize(nextPageSize);
393
+ state.setPage(1);
394
+ const normalized = {
395
+ version: 1,
396
+ columns: configurableColumns.map(column => ({
397
+ key: column.key,
398
+ visible: nextVisible.includes(column.key),
399
+ })),
400
+ filters: {
401
+ ...(keyword ? { keyword } : {}),
402
+ ...(Object.keys(filterValues).length ? { values: filterValues } : {}),
403
+ },
404
+ sorts: [{
405
+ field: nextSort.field,
406
+ direction: nextSort.order === 'asc' ? 'ascend' : 'descend',
407
+ }],
408
+ density: nextDensity,
409
+ pageSize: nextPageSize,
410
+ };
411
+ setHasSavedPreference(Boolean(preference));
412
+ setSavedPreferenceFingerprint(preferenceFingerprint(normalized));
413
+ setPreferenceReady(true);
414
+ })
415
+ .catch(() => {
416
+ if (!active)
417
+ return;
418
+ setHasSavedPreference(false);
419
+ setSavedPreferenceFingerprint(preferenceFingerprint(defaults));
420
+ setPreferenceReady(true);
421
+ });
422
+ return () => {
423
+ active = false;
424
+ };
425
+ // Resource changes remount the generated page and own preference scope.
426
+ // eslint-disable-next-line react-hooks/exhaustive-deps
427
+ }, [code]);
428
+ const firstVisibleBusinessField = fields.find(field => visibleColumnKeys.includes(field.key));
265
429
  const columns = useMemo(() => [
266
430
  ...fields
267
431
  .filter((field) => visibleColumnKeys.includes(field.key))
@@ -269,18 +433,27 @@ function GeneratedDesktopList({ definition, paths }) {
269
433
  title: field.label,
270
434
  dataIndex: field.key,
271
435
  key: field.key,
436
+ align: field.type === 'number.integer' || field.type === 'number.decimal'
437
+ ? 'right'
438
+ : undefined,
272
439
  sorter: Boolean(field.sortable),
273
440
  render: (value, record) => {
274
441
  const rendered = (_jsx(SurfaceFieldValue, { field: field, resourceCode: code, value: value }));
275
- return field.key === fields[0]?.key && generated.detail ? (_jsx("a", { onClick: () => navigate(resourceRecordPath(paths.detail, record.id)), children: rendered })) : rendered;
442
+ return field.key === firstVisibleBusinessField?.key && generated.detail ? (_jsx("a", { onClick: () => navigate(resourceRecordPath(paths.detail, record.id)), children: rendered })) : rendered;
276
443
  },
277
444
  })),
278
- {
279
- title: '更新时间',
280
- dataIndex: 'updated_at',
281
- key: 'updated_at',
282
- render: (value) => (value ? new Date(String(value)).toLocaleString('zh-CN') : '-'),
283
- },
445
+ ...(visibleColumnKeys.includes('created_at') ? [{
446
+ title: '创建时间',
447
+ dataIndex: 'created_at',
448
+ key: 'created_at',
449
+ render: (value) => (value ? new Date(String(value)).toLocaleString('zh-CN') : '-'),
450
+ }] : []),
451
+ ...(visibleColumnKeys.includes('updated_at') ? [{
452
+ title: '更新时间',
453
+ dataIndex: 'updated_at',
454
+ key: 'updated_at',
455
+ render: (value) => (value ? new Date(String(value)).toLocaleString('zh-CN') : '-'),
456
+ }] : []),
284
457
  {
285
458
  title: '操作',
286
459
  key: 'actions',
@@ -305,6 +478,7 @@ function GeneratedDesktopList({ definition, paths }) {
305
478
  capabilities.update,
306
479
  code,
307
480
  fields,
481
+ firstVisibleBusinessField,
308
482
  hasCapability,
309
483
  message,
310
484
  name,
@@ -327,6 +501,61 @@ function GeneratedDesktopList({ definition, paths }) {
327
501
  setExporting(false);
328
502
  }
329
503
  };
504
+ const savePreference = async () => {
505
+ setPreferenceSaving(true);
506
+ try {
507
+ const saved = await saveResourceListPreference(listKey, preferencePayload());
508
+ setSavedPreferenceFingerprint(preferenceFingerprint(saved));
509
+ setHasSavedPreference(true);
510
+ message.success('列表设置已保存');
511
+ }
512
+ catch (error) {
513
+ message.error(error instanceof Error ? error.message : '列表设置保存失败');
514
+ }
515
+ finally {
516
+ setPreferenceSaving(false);
517
+ }
518
+ };
519
+ const restorePreference = async () => {
520
+ setPreferenceSaving(true);
521
+ try {
522
+ await resetResourceListPreference(listKey);
523
+ const nextVisible = configurableColumns.map(column => column.key);
524
+ const defaultSortField = surface.list?.defaultSort?.field || fields[0]?.key || 'id';
525
+ const defaultSortOrder = surface.list?.defaultSort?.order || 'asc';
526
+ const defaultPageSize = surface.list?.defaultPageSize || 20;
527
+ setVisibleColumnKeys(nextVisible);
528
+ setDensity('middle');
529
+ state.setDraft({});
530
+ state.setQuery({});
531
+ state.setSort({ field: defaultSortField, order: defaultSortOrder });
532
+ state.setPageSize(defaultPageSize);
533
+ state.setPage(1);
534
+ const restored = {
535
+ version: 1,
536
+ columns: configurableColumns.map(column => ({
537
+ key: column.key,
538
+ visible: true,
539
+ })),
540
+ filters: {},
541
+ sorts: [{
542
+ field: defaultSortField,
543
+ direction: defaultSortOrder === 'asc' ? 'ascend' : 'descend',
544
+ }],
545
+ density: 'middle',
546
+ pageSize: defaultPageSize,
547
+ };
548
+ setSavedPreferenceFingerprint(preferenceFingerprint(restored));
549
+ setHasSavedPreference(false);
550
+ message.success('已恢复平台默认设置');
551
+ }
552
+ catch (error) {
553
+ message.error(error instanceof Error ? error.message : '恢复默认设置失败');
554
+ }
555
+ finally {
556
+ setPreferenceSaving(false);
557
+ }
558
+ };
330
559
  const filterFields = (surface.list?.filterFields || []).filter((field) => readableFieldCodes.has(field));
331
560
  const searchableFields = (surface.list?.searchableFields || []).filter((field) => readableFieldCodes.has(field));
332
561
  const primaryFilterFields = filterFields.slice(0, 2);
@@ -365,7 +594,7 @@ function GeneratedDesktopList({ definition, paths }) {
365
594
  })),
366
595
  ];
367
596
  const columnMenu = {
368
- items: fields.map((field) => ({ key: field.key, label: field.label })),
597
+ items: configurableColumns.map((column) => ({ key: column.key, label: column.label })),
369
598
  multiple: true,
370
599
  selectable: true,
371
600
  selectedKeys: visibleColumnKeys,
@@ -412,11 +641,11 @@ function GeneratedDesktopList({ definition, paths }) {
412
641
  }, open: moreFiltersOpen, title: "\u66F4\u591A\u7B5B\u9009", width: 860, children: _jsx("div", { className: "oxa-more-filter-grid", children: additionalFilterFields.map(key => {
413
642
  const field = fieldFor(surface, key);
414
643
  return (_jsxs("div", { className: "oxa-more-filter-field", children: [_jsx("label", { children: field.label }), _jsx(SurfaceFilterControl, { field: field, resourceCode: code, onChange: (value) => setMoreFilterDraft(current => ({ ...current, [key]: value })), value: moreFilterDraft[key] })] }, key));
415
- }) }) }), _jsxs("div", { className: "oxa-list-toolbar", children: [_jsxs(Space, { className: "oxa-list-toolbar-primary", wrap: true, children: [generated.create && hasCapability(capabilities.create) && (_jsxs(Button, { icon: _jsx(PlusOutlined, {}), onClick: () => navigate(paths.create), type: "primary", children: ["\u65B0\u589E", name] })), generated.create && hasCapability(capabilities.create) && (_jsx(ResourceImportButton, { code: code, name: name, surface: surface, writableFieldCodes: importWritableFieldCodes, onCompleted: () => state.list.query.refetch() })), _jsx(Button, { icon: _jsx(ExportOutlined, {}), loading: exporting, onClick: () => void handleExport(), children: "\u5BFC\u51FA" }), toolbarContributions.map((contribution) => (_jsx(Fragment, { children: contribution.render({
644
+ }) }) }), _jsxs("div", { className: "oxa-list-toolbar", children: [_jsxs(Space, { className: "oxa-list-toolbar-primary", wrap: true, children: [generated.create && hasCapability(capabilities.create) && (_jsxs(Button, { icon: _jsx(PlusOutlined, {}), onClick: () => navigate(paths.create), type: "primary", children: ["\u65B0\u589E", name] })), standardWorkflow?.processOperationCode && (_jsx(WorkflowResourceImportButton, { code: code, name: name, onCompleted: () => state.list.query.refetch(), processOperationCode: standardWorkflow.processOperationCode, surface: surface, workflowCode: standardWorkflow.code, writableFieldCodes: workflowImportFieldCodes })), generated.create && hasCapability(capabilities.create) && (_jsx(ResourceImportButton, { code: code, name: name, surface: surface, writableFieldCodes: importWritableFieldCodes, onCompleted: () => state.list.query.refetch() })), _jsx(Button, { icon: _jsx(ExportOutlined, {}), loading: exporting, onClick: () => void handleExport(), children: "\u5BFC\u51FA" }), toolbarContributions.map((contribution) => (_jsx(Fragment, { children: contribution.render({
416
645
  resource: code,
417
646
  selectedRecords: selectedRows,
418
647
  refresh: () => state.list.query.refetch(),
419
- }) }, contribution.code)))] }), _jsxs(Space, { className: "oxa-list-toolbar-secondary", size: 4, children: [_jsx(Tooltip, { title: "\u5237\u65B0", children: _jsx(Button, { "aria-label": "\u5237\u65B0\u6570\u636E", icon: _jsx(ReloadOutlined, {}), loading: state.list.query.isFetching, onClick: () => void state.list.query.refetch(), type: "text" }) }), _jsx(Dropdown, { menu: columnMenu, trigger: ['click'], children: _jsx(Button, { icon: _jsx(SettingOutlined, {}), type: "text", children: "\u5217\u8BBE\u7F6E" }) }), _jsx(Dropdown, { menu: densityMenu, trigger: ['click'], children: _jsx(Button, { icon: _jsx(ColumnHeightOutlined, {}), type: "text", children: "\u5BC6\u5EA6" }) })] })] }), _jsx(ResourceBatchActions, { canDelete: Boolean(generated.delete && hasCapability(capabilities.delete)), code: code, name: name, onClear: () => setSelectedRowKeys([]), onCompleted: () => state.list.query.refetch(), rows: selectedRows, surface: surface, writableFields: batchWritableFields }), _jsx(Table, { columns: columns, dataSource: rows, loading: state.list.query.isFetching, locale: { emptyText: _jsx(Empty, { description: `暂无${name}` }) }, rowKey: "id", rowSelection: canBatch
648
+ }) }, contribution.code)))] }), _jsxs(Space, { className: "oxa-list-toolbar-secondary", size: 4, children: [preferenceDirty && (_jsx(Button, { icon: _jsx(SaveOutlined, {}), loading: preferenceSaving, onClick: () => void savePreference(), type: "primary", children: "\u4FDD\u5B58\u8BBE\u7F6E" })), hasSavedPreference && !preferenceDirty && (_jsx(Button, { icon: _jsx(UndoOutlined, {}), loading: preferenceSaving, onClick: () => void restorePreference(), type: "text", children: "\u6062\u590D\u9ED8\u8BA4" })), _jsx(Tooltip, { title: "\u5237\u65B0", children: _jsx(Button, { "aria-label": "\u5237\u65B0\u6570\u636E", icon: _jsx(ReloadOutlined, {}), loading: state.list.query.isFetching, onClick: () => void state.list.query.refetch(), type: "text" }) }), _jsx(Dropdown, { menu: columnMenu, trigger: ['click'], children: _jsx(Button, { icon: _jsx(SettingOutlined, {}), type: "text", children: "\u5217\u8BBE\u7F6E" }) }), _jsx(Dropdown, { menu: densityMenu, trigger: ['click'], children: _jsx(Button, { icon: _jsx(ColumnHeightOutlined, {}), type: "text", children: "\u5BC6\u5EA6" }) })] })] }), _jsx(ResourceBatchActions, { canDelete: Boolean(generated.delete && hasCapability(capabilities.delete)), code: code, name: name, onClear: () => setSelectedRowKeys([]), onCompleted: () => state.list.query.refetch(), rows: selectedRows, surface: surface, writableFields: batchWritableFields }), _jsx(Table, { columns: columns, dataSource: rows, loading: state.list.query.isFetching, locale: { emptyText: _jsx(Empty, { description: `暂无${name}` }) }, rowKey: "id", rowSelection: canBatch
420
649
  ? {
421
650
  selectedRowKeys,
422
651
  onChange: (keys) => {
@@ -682,7 +911,6 @@ function GeneratedResourceDetailPage({ definition, paths, variant }) {
682
911
  resource: definition.code,
683
912
  refresh: () => query.query.refetch(),
684
913
  }) }, contribution.code))) })) : null,
685
- auditTargetId: `${definition.code}-audit`,
686
914
  backLabel: `返回${definition.name}`,
687
915
  backPath: paths.list || paths.fallback,
688
916
  editCapability: definition.surface.generated?.update
@@ -694,8 +922,6 @@ function GeneratedResourceDetailPage({ definition, paths, variant }) {
694
922
  error: query.query.isError || (!query.query.isFetching && !record) ? query.query.error?.message || '记录不存在' : undefined,
695
923
  hero,
696
924
  loading: query.query.isFetching,
697
- meta: record ? _jsxs("span", { children: ["\u6700\u8FD1\u66F4\u65B0 ", record.updated_at ? new Date(record.updated_at).toLocaleString('zh-CN') : '-'] }) : null,
698
- onAuditOpen: () => setAuditExpanded(true),
699
925
  readCapability: definition.capabilities.read,
700
926
  resource: definition.code,
701
927
  surface: definition.surface,