openxiangda-cli 2.0.0-alpha.89 → 2.0.0-alpha.91

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 (77) 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 +3 -3
  16. package/template/apps/server/package.json +1 -1
  17. package/template/apps/server/src/app.module.ts +1 -1
  18. package/template/apps/server/src/main.ts +1 -1
  19. package/template/apps/web/e2e/client-fixture.ts +5 -0
  20. package/template/apps/web/e2e/data-api-live-fixture.tsx +19 -14
  21. package/template/apps/web/e2e/field-protocol-fixture.tsx +87 -20
  22. package/template/apps/web/e2e/field-protocol.spec.ts +86 -0
  23. package/template/apps/web/e2e/resources.spec.ts +20 -181
  24. package/template/apps/web/field-protocol.e2e.html +3 -0
  25. package/template/apps/web/package.json +2 -5
  26. package/template/apps/web/src/main.tsx +12 -60
  27. package/template/apps/web/test/contracts.test.ts +52 -104
  28. package/template/openxiangda.config.ts +1 -1
  29. package/template/package.json +1 -3
  30. package/template/packages/contracts/src/generated.ts +1 -0
  31. package/template/scripts/verify-template-budget.mjs +2 -2
  32. package/template/apps/web/src/AuthoritativeSelector.tsx +0 -661
  33. package/template/apps/web/src/FilePreviewPage.tsx +0 -324
  34. package/template/apps/web/src/RoleSubjectSelect.tsx +0 -128
  35. package/template/apps/web/src/Shell.tsx +0 -445
  36. package/template/apps/web/src/appearance.tsx +0 -147
  37. package/template/apps/web/src/components/platform-fields/AddressField.tsx +0 -338
  38. package/template/apps/web/src/components/platform-fields/AttachmentFileList.tsx +0 -245
  39. package/template/apps/web/src/components/platform-fields/CascadeField.tsx +0 -49
  40. package/template/apps/web/src/components/platform-fields/DateTimeField.tsx +0 -148
  41. package/template/apps/web/src/components/platform-fields/JsonField.tsx +0 -77
  42. package/template/apps/web/src/components/platform-fields/LocationField.tsx +0 -164
  43. package/template/apps/web/src/components/platform-fields/PlatformDirectoryPicker.tsx +0 -673
  44. package/template/apps/web/src/components/platform-fields/ResourceReferenceField.tsx +0 -67
  45. package/template/apps/web/src/components/platform-fields/RichTextField.tsx +0 -196
  46. package/template/apps/web/src/components/platform-fields/SignatureField.tsx +0 -315
  47. package/template/apps/web/src/components/platform-fields/SubtableField.tsx +0 -553
  48. package/template/apps/web/src/components/platform-fields/address-value.ts +0 -80
  49. package/template/apps/web/src/components/platform-fields/cascade-value.ts +0 -66
  50. package/template/apps/web/src/components/platform-fields/directory-value.ts +0 -53
  51. package/template/apps/web/src/components/platform-fields/field-form-codec.ts +0 -98
  52. package/template/apps/web/src/components/platform-fields/location-value.ts +0 -87
  53. package/template/apps/web/src/components/platform-fields/resource-query.ts +0 -131
  54. package/template/apps/web/src/components/platform-fields/rich-text-value.ts +0 -59
  55. package/template/apps/web/src/components/platform-fields/subtable-value.ts +0 -187
  56. package/template/apps/web/src/components/resource/GeneratedResourceCrud.tsx +0 -1184
  57. package/template/apps/web/src/components/resource/ResourceBatchActions.tsx +0 -326
  58. package/template/apps/web/src/components/resource/StandardResourcePages.tsx +0 -392
  59. package/template/apps/web/src/components/resource/SurfaceFields.tsx +0 -915
  60. package/template/apps/web/src/components/resource/generated-resource-definition.ts +0 -18
  61. package/template/apps/web/src/components/resource/resource-import.ts +0 -205
  62. package/template/apps/web/src/data-provider.ts +0 -72
  63. package/template/apps/web/src/platform-client.ts +0 -708
  64. package/template/apps/web/src/runtime-meta.ts +0 -75
  65. package/template/apps/web/src/runtime.tsx +0 -227
  66. package/template/apps/web/src/styles.css +0 -1941
  67. package/template/apps/web/test/address-field.test.ts +0 -66
  68. package/template/apps/web/test/cascade-value.test.ts +0 -68
  69. package/template/apps/web/test/directory-value.test.ts +0 -55
  70. package/template/apps/web/test/field-bounds.test.ts +0 -17
  71. package/template/apps/web/test/field-form-codec.test.ts +0 -85
  72. package/template/apps/web/test/location-field.test.ts +0 -83
  73. package/template/apps/web/test/resource-import.test.ts +0 -143
  74. package/template/apps/web/test/resource-query.test.ts +0 -144
  75. package/template/apps/web/test/rich-json-field.test.ts +0 -53
  76. package/template/apps/web/test/signature-serial-field.test.ts +0 -40
  77. 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
- }