openxiangda-cli 2.0.0-alpha.86 → 2.0.0-alpha.90

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 (78) hide show
  1. package/README.md +2 -2
  2. package/bin/run.js +1 -0
  3. package/dist/commands/skill.d.ts +26 -0
  4. package/dist/commands/skill.d.ts.map +1 -0
  5. package/dist/commands/skill.js +43 -0
  6. package/dist/commands/skill.js.map +1 -0
  7. package/dist/create-workspace.d.ts.map +1 -1
  8. package/dist/create-workspace.js +3 -3
  9. package/dist/create-workspace.js.map +1 -1
  10. package/dist/toolchain-capsule.d.ts.map +1 -1
  11. package/dist/toolchain-capsule.js +4 -8
  12. package/dist/toolchain-capsule.js.map +1 -1
  13. package/package.json +6 -7
  14. package/template/AGENTS.md +2 -1
  15. package/template/README.md +5 -5
  16. package/template/apps/server/package.json +1 -1
  17. package/template/apps/server/src/app.module.ts +14 -1
  18. package/template/apps/server/src/main.ts +1 -1
  19. package/template/apps/server/test/smoke.test.ts +3 -1
  20. package/template/apps/web/e2e/client-fixture.ts +5 -0
  21. package/template/apps/web/e2e/data-api-live-fixture.tsx +19 -14
  22. package/template/apps/web/e2e/field-protocol-fixture.tsx +87 -20
  23. package/template/apps/web/e2e/field-protocol.spec.ts +86 -0
  24. package/template/apps/web/e2e/resources.spec.ts +20 -181
  25. package/template/apps/web/field-protocol.e2e.html +3 -0
  26. package/template/apps/web/package.json +2 -5
  27. package/template/apps/web/src/main.tsx +12 -60
  28. package/template/apps/web/test/contracts.test.ts +52 -104
  29. package/template/openxiangda.config.ts +2 -2
  30. package/template/package.json +1 -3
  31. package/template/packages/contracts/src/generated.ts +27 -0
  32. package/template/scripts/verify-template-budget.mjs +2 -2
  33. package/template/apps/web/src/AuthoritativeSelector.tsx +0 -661
  34. package/template/apps/web/src/FilePreviewPage.tsx +0 -324
  35. package/template/apps/web/src/RoleSubjectSelect.tsx +0 -128
  36. package/template/apps/web/src/Shell.tsx +0 -445
  37. package/template/apps/web/src/appearance.tsx +0 -147
  38. package/template/apps/web/src/components/platform-fields/AddressField.tsx +0 -338
  39. package/template/apps/web/src/components/platform-fields/AttachmentFileList.tsx +0 -245
  40. package/template/apps/web/src/components/platform-fields/CascadeField.tsx +0 -49
  41. package/template/apps/web/src/components/platform-fields/DateTimeField.tsx +0 -148
  42. package/template/apps/web/src/components/platform-fields/JsonField.tsx +0 -77
  43. package/template/apps/web/src/components/platform-fields/LocationField.tsx +0 -164
  44. package/template/apps/web/src/components/platform-fields/PlatformDirectoryPicker.tsx +0 -673
  45. package/template/apps/web/src/components/platform-fields/ResourceReferenceField.tsx +0 -67
  46. package/template/apps/web/src/components/platform-fields/RichTextField.tsx +0 -196
  47. package/template/apps/web/src/components/platform-fields/SignatureField.tsx +0 -315
  48. package/template/apps/web/src/components/platform-fields/SubtableField.tsx +0 -553
  49. package/template/apps/web/src/components/platform-fields/address-value.ts +0 -80
  50. package/template/apps/web/src/components/platform-fields/cascade-value.ts +0 -66
  51. package/template/apps/web/src/components/platform-fields/directory-value.ts +0 -53
  52. package/template/apps/web/src/components/platform-fields/field-form-codec.ts +0 -98
  53. package/template/apps/web/src/components/platform-fields/location-value.ts +0 -87
  54. package/template/apps/web/src/components/platform-fields/resource-query.ts +0 -131
  55. package/template/apps/web/src/components/platform-fields/rich-text-value.ts +0 -59
  56. package/template/apps/web/src/components/platform-fields/subtable-value.ts +0 -187
  57. package/template/apps/web/src/components/resource/GeneratedResourceCrud.tsx +0 -1184
  58. package/template/apps/web/src/components/resource/ResourceBatchActions.tsx +0 -326
  59. package/template/apps/web/src/components/resource/StandardResourcePages.tsx +0 -392
  60. package/template/apps/web/src/components/resource/SurfaceFields.tsx +0 -915
  61. package/template/apps/web/src/components/resource/generated-resource-definition.ts +0 -18
  62. package/template/apps/web/src/components/resource/resource-import.ts +0 -205
  63. package/template/apps/web/src/data-provider.ts +0 -72
  64. package/template/apps/web/src/platform-client.ts +0 -708
  65. package/template/apps/web/src/runtime-meta.ts +0 -75
  66. package/template/apps/web/src/runtime.tsx +0 -227
  67. package/template/apps/web/src/styles.css +0 -1941
  68. package/template/apps/web/test/address-field.test.ts +0 -66
  69. package/template/apps/web/test/cascade-value.test.ts +0 -68
  70. package/template/apps/web/test/directory-value.test.ts +0 -55
  71. package/template/apps/web/test/field-bounds.test.ts +0 -17
  72. package/template/apps/web/test/field-form-codec.test.ts +0 -85
  73. package/template/apps/web/test/location-field.test.ts +0 -83
  74. package/template/apps/web/test/resource-import.test.ts +0 -143
  75. package/template/apps/web/test/resource-query.test.ts +0 -144
  76. package/template/apps/web/test/rich-json-field.test.ts +0 -53
  77. package/template/apps/web/test/signature-serial-field.test.ts +0 -40
  78. package/template/apps/web/test/subtable-value.test.ts +0 -144
@@ -1,392 +0,0 @@
1
- import {
2
- ArrowLeftOutlined,
3
- EditOutlined,
4
- ExportOutlined,
5
- EyeOutlined,
6
- HistoryOutlined,
7
- PlusOutlined,
8
- } from '@ant-design/icons';
9
- import {
10
- Alert,
11
- Button,
12
- Card,
13
- Result,
14
- Space,
15
- Spin,
16
- Typography,
17
- } from 'antd';
18
- import type { DataResourceSurface } from 'openxiangda-contracts/browser';
19
- import type { ReactNode } from 'react';
20
- import { useNavigate } from 'react-router-dom';
21
- import { Shell } from '../../Shell';
22
- import { useRuntime } from '../../runtime';
23
-
24
- export interface StandardResourcePageProps {
25
- resource: string;
26
- surface?: DataResourceSurface;
27
- title: string;
28
- description?: string;
29
- }
30
-
31
- interface ResourceListPageProps extends StandardResourcePageProps {
32
- readCapability: string;
33
- createCapability?: string;
34
- createPath?: string;
35
- onExport?: () => void;
36
- importDisabledReason?: string;
37
- children: ReactNode;
38
- }
39
-
40
- /**
41
- * The standard admin list shell. Data fetching stays in the app's Refine
42
- * provider; this component owns the stable page chrome and CRUD actions.
43
- */
44
- export function ResourceListPage({
45
- resource,
46
- surface,
47
- title,
48
- readCapability,
49
- children,
50
- }: ResourceListPageProps) {
51
- const { hasCapability } = useRuntime();
52
- if (!hasCapability(readCapability)) {
53
- return (
54
- <Shell>
55
- <Result status="403" title={`当前平台用户无${title}页面权限`} />
56
- </Shell>
57
- );
58
- }
59
- return (
60
- <Shell>
61
- <Card
62
- className="oxa-list-card"
63
- data-resource={resource}
64
- data-surface-layout={surface?.list ? 'standard' : undefined}
65
- >
66
- <div className="oxa-list-surface">{children}</div>
67
- </Card>
68
- </Shell>
69
- );
70
- }
71
-
72
- /** Mobile list shell: the same capability gate with a compact, app-owned list. */
73
- export function MobileResourceListPage({
74
- resource,
75
- surface,
76
- title,
77
- description,
78
- readCapability,
79
- createCapability,
80
- createPath,
81
- onExport,
82
- children,
83
- }: ResourceListPageProps) {
84
- const navigate = useNavigate();
85
- const { hasCapability } = useRuntime();
86
- if (!hasCapability(readCapability)) {
87
- return <div className="oxa-mobile-page"><Result status="403" title={`当前平台用户无${title}页面权限`} /></div>;
88
- }
89
- return (
90
- <div className="oxa-mobile-page" data-resource={resource} data-surface-layout={surface?.list ? 'standard' : undefined}>
91
- <header className="oxa-mobile-header">
92
- <div>
93
- <Typography.Title level={3}>{title}</Typography.Title>
94
- {description && <Typography.Text type="secondary">{description}</Typography.Text>}
95
- </div>
96
- <Space>
97
- {onExport && <Button icon={<ExportOutlined />} onClick={onExport}>导出</Button>}
98
- {createCapability && createPath && hasCapability(createCapability) && (
99
- <Button icon={<PlusOutlined />} onClick={() => navigate(createPath)} type="primary">新增</Button>
100
- )}
101
- </Space>
102
- </header>
103
- <Alert title="移动端使用独立列表交互;数据查询、权限和 PC 端保持一致。" showIcon type="info" />
104
- {children}
105
- </div>
106
- );
107
- }
108
-
109
- interface ResourceFormPageProps extends StandardResourcePageProps {
110
- mode: 'create' | 'edit';
111
- capability: string;
112
- loading?: boolean;
113
- notFound?: boolean;
114
- backPath: string;
115
- backLabel: string;
116
- detailPath?: string;
117
- recordSummary?: ReactNode;
118
- children: ReactNode;
119
- }
120
-
121
- /** The standard create/edit lifecycle: capability, loading, not-found, hero. */
122
- export function ResourceFormPage({
123
- resource,
124
- surface,
125
- title,
126
- mode,
127
- capability,
128
- loading = false,
129
- notFound = false,
130
- backPath,
131
- backLabel,
132
- detailPath,
133
- recordSummary,
134
- children,
135
- }: ResourceFormPageProps) {
136
- const navigate = useNavigate();
137
- const { hasCapability } = useRuntime();
138
- if (!hasCapability(capability)) {
139
- return (
140
- <Shell>
141
- <Result status="403" title="当前平台用户无此操作权限" />
142
- </Shell>
143
- );
144
- }
145
- if (loading) {
146
- return (
147
- <Shell>
148
- <div className="oxa-page-loading">
149
- <Spin />
150
- </div>
151
- </Shell>
152
- );
153
- }
154
- if (notFound) {
155
- return (
156
- <Shell>
157
- <Result status="404" title="记录不存在或不在数据范围内" />
158
- </Shell>
159
- );
160
- }
161
- return (
162
- <Shell>
163
- <Card
164
- className="oxa-edit-hero"
165
- data-resource={resource}
166
- data-surface-layout={surface?.form?.layout || 'flat'}
167
- >
168
- <div className="oxa-edit-hero-title">
169
- <div>
170
- <Button icon={<ArrowLeftOutlined />} onClick={() => navigate(backPath)} type="link">
171
- {backLabel}
172
- </Button>
173
- <Typography.Title level={2}>
174
- {mode === 'create' ? `新增${title}` : `编辑${title}`}
175
- </Typography.Title>
176
- {recordSummary && <Typography.Text type="secondary">{recordSummary}</Typography.Text>}
177
- </div>
178
- {detailPath && (
179
- <Button icon={<EyeOutlined />} onClick={() => navigate(detailPath)}>
180
- 查看详情
181
- </Button>
182
- )}
183
- </div>
184
- <Alert
185
- title="仅显示当前角色可编辑的字段;保存时将校验数据版本与权限范围。"
186
- showIcon
187
- type="info"
188
- />
189
- </Card>
190
- {children}
191
- </Shell>
192
- );
193
- }
194
-
195
- export function MobileResourceFormPage({
196
- resource,
197
- surface,
198
- title,
199
- mode,
200
- capability,
201
- loading = false,
202
- notFound = false,
203
- backPath,
204
- backLabel,
205
- recordSummary,
206
- children,
207
- }: ResourceFormPageProps) {
208
- const navigate = useNavigate();
209
- const { hasCapability } = useRuntime();
210
- if (!hasCapability(capability)) {
211
- return <div className="oxa-mobile-page"><Result status="403" title="当前平台用户无此操作权限" /></div>;
212
- }
213
- if (loading) {
214
- return <div className="oxa-mobile-page"><Spin /></div>;
215
- }
216
- if (notFound) {
217
- return <div className="oxa-mobile-page"><Result status="404" title="记录不存在或不在数据范围内" /></div>;
218
- }
219
- return (
220
- <div
221
- className="oxa-mobile-page"
222
- data-resource={resource}
223
- data-surface-layout={surface?.form?.layout || 'flat'}
224
- >
225
- <header className="oxa-mobile-header">
226
- <Button icon={<ArrowLeftOutlined />} onClick={() => navigate(backPath)} type="link">
227
- {backLabel}
228
- </Button>
229
- <Typography.Title level={3}>{mode === 'create' ? `新增${title}` : `编辑${title}`}</Typography.Title>
230
- {recordSummary && <Typography.Text type="secondary">{recordSummary}</Typography.Text>}
231
- </header>
232
- <Alert title="移动端使用独立控件,提交值与 PC 端保持一致。" showIcon type="info" />
233
- {children}
234
- </div>
235
- );
236
- }
237
-
238
- interface ResourceDetailPageProps extends StandardResourcePageProps {
239
- readCapability: string;
240
- loading?: boolean;
241
- error?: string;
242
- backPath: string;
243
- backLabel: string;
244
- editCapability?: string;
245
- editPath?: string;
246
- auditTargetId?: string;
247
- onAuditOpen?: () => void;
248
- hero: ReactNode;
249
- meta?: ReactNode;
250
- children: ReactNode;
251
- }
252
-
253
- /** The standard detail lifecycle and audit/edit navigation. */
254
- export function ResourceDetailPage({
255
- resource,
256
- surface,
257
- title,
258
- readCapability,
259
- loading = false,
260
- error,
261
- backPath,
262
- backLabel,
263
- editCapability,
264
- editPath,
265
- auditTargetId,
266
- onAuditOpen,
267
- hero,
268
- meta,
269
- children,
270
- }: ResourceDetailPageProps) {
271
- const navigate = useNavigate();
272
- const { hasCapability } = useRuntime();
273
- if (!hasCapability(readCapability)) {
274
- return (
275
- <Shell>
276
- <Result status="403" title={`当前平台用户无${title}页面权限`} />
277
- </Shell>
278
- );
279
- }
280
- if (loading) {
281
- return (
282
- <Shell>
283
- <div className="oxa-page-loading">
284
- <Spin />
285
- </div>
286
- </Shell>
287
- );
288
- }
289
- if (error) {
290
- return (
291
- <Shell>
292
- <Result status="403" subTitle={error} title="无法访问" />
293
- </Shell>
294
- );
295
- }
296
- return (
297
- <Shell>
298
- <Card
299
- className="oxa-detail-hero"
300
- data-resource={resource}
301
- data-surface-layout={surface?.detail?.layout || 'flat'}
302
- >
303
- <div className="oxa-detail-hero-top">
304
- <Button
305
- aria-label="返回列表"
306
- icon={<ArrowLeftOutlined />}
307
- onClick={() => navigate(backPath)}
308
- type="link"
309
- >
310
- {backLabel}
311
- </Button>
312
- <Space>
313
- {auditTargetId && (
314
- <Button
315
- icon={<HistoryOutlined />}
316
- onClick={() => {
317
- onAuditOpen?.();
318
- window.requestAnimationFrame(() =>
319
- document
320
- .getElementById(auditTargetId)
321
- ?.scrollIntoView({ behavior: 'smooth', block: 'center' }),
322
- );
323
- }}
324
- >
325
- 操作记录
326
- </Button>
327
- )}
328
- {editCapability && editPath && hasCapability(editCapability) && (
329
- <Button
330
- icon={<EditOutlined />}
331
- onClick={() => navigate(editPath)}
332
- type="primary"
333
- >
334
- 编辑
335
- </Button>
336
- )}
337
- </Space>
338
- </div>
339
- <div className="oxa-detail-hero-main">
340
- {hero}
341
- {meta && <Space className="oxa-record-meta" separator={<span>·</span>}>{meta}</Space>}
342
- </div>
343
- </Card>
344
- {children}
345
- </Shell>
346
- );
347
- }
348
-
349
- /** Mobile detail shell: keeps the resource lifecycle and audit/edit actions stable. */
350
- export function MobileResourceDetailPage({
351
- resource,
352
- surface,
353
- title,
354
- readCapability,
355
- loading = false,
356
- error,
357
- backPath,
358
- backLabel,
359
- editCapability,
360
- editPath,
361
- auditTargetId,
362
- onAuditOpen,
363
- hero,
364
- meta,
365
- children,
366
- }: ResourceDetailPageProps) {
367
- const navigate = useNavigate();
368
- const { hasCapability } = useRuntime();
369
- if (!hasCapability(readCapability)) {
370
- return <div className="oxa-mobile-page"><Result status="403" title={`当前平台用户无${title}页面权限`} /></div>;
371
- }
372
- if (loading) return <div className="oxa-mobile-page"><Spin /></div>;
373
- if (error) return <div className="oxa-mobile-page"><Result status="403" subTitle={error} title="无法访问" /></div>;
374
- return (
375
- <div className="oxa-mobile-page" data-resource={resource} data-surface-layout={surface?.detail?.layout || 'flat'}>
376
- <header className="oxa-mobile-header">
377
- <Button aria-label="返回列表" icon={<ArrowLeftOutlined />} onClick={() => navigate(backPath)} type="link">
378
- {backLabel}
379
- </Button>
380
- <Space>
381
- {auditTargetId && <Button icon={<HistoryOutlined />} onClick={() => { onAuditOpen?.(); window.requestAnimationFrame(() => document.getElementById(auditTargetId)?.scrollIntoView({ behavior: 'smooth', block: 'center' })); }}>操作记录</Button>}
382
- {editCapability && editPath && hasCapability(editCapability) && <Button icon={<EditOutlined />} onClick={() => navigate(editPath)} type="primary">编辑</Button>}
383
- </Space>
384
- </header>
385
- <Card className="oxa-detail-hero" data-resource-hero="mobile">
386
- {hero}
387
- {meta && <Space className="oxa-record-meta" separator={<span>·</span>}>{meta}</Space>}
388
- </Card>
389
- {children}
390
- </div>
391
- );
392
- }