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.
- package/README.md +2 -2
- package/bin/run.js +1 -0
- package/dist/commands/skill.d.ts +26 -0
- package/dist/commands/skill.d.ts.map +1 -0
- package/dist/commands/skill.js +43 -0
- package/dist/commands/skill.js.map +1 -0
- package/dist/create-workspace.d.ts.map +1 -1
- package/dist/create-workspace.js +3 -3
- package/dist/create-workspace.js.map +1 -1
- package/dist/toolchain-capsule.d.ts.map +1 -1
- package/dist/toolchain-capsule.js +4 -8
- package/dist/toolchain-capsule.js.map +1 -1
- package/package.json +6 -7
- package/template/AGENTS.md +2 -1
- package/template/README.md +3 -3
- package/template/apps/server/package.json +1 -1
- package/template/apps/server/src/app.module.ts +1 -1
- package/template/apps/server/src/main.ts +1 -1
- package/template/apps/web/e2e/client-fixture.ts +5 -0
- package/template/apps/web/e2e/data-api-live-fixture.tsx +19 -14
- package/template/apps/web/e2e/field-protocol-fixture.tsx +87 -20
- package/template/apps/web/e2e/field-protocol.spec.ts +86 -0
- package/template/apps/web/e2e/resources.spec.ts +20 -181
- package/template/apps/web/field-protocol.e2e.html +3 -0
- package/template/apps/web/package.json +2 -5
- package/template/apps/web/src/main.tsx +12 -60
- package/template/apps/web/test/contracts.test.ts +52 -104
- package/template/openxiangda.config.ts +1 -1
- package/template/package.json +1 -3
- package/template/packages/contracts/src/generated.ts +1 -0
- package/template/scripts/verify-template-budget.mjs +2 -2
- package/template/apps/web/src/AuthoritativeSelector.tsx +0 -661
- package/template/apps/web/src/FilePreviewPage.tsx +0 -324
- package/template/apps/web/src/RoleSubjectSelect.tsx +0 -128
- package/template/apps/web/src/Shell.tsx +0 -445
- package/template/apps/web/src/appearance.tsx +0 -147
- package/template/apps/web/src/components/platform-fields/AddressField.tsx +0 -338
- package/template/apps/web/src/components/platform-fields/AttachmentFileList.tsx +0 -245
- package/template/apps/web/src/components/platform-fields/CascadeField.tsx +0 -49
- package/template/apps/web/src/components/platform-fields/DateTimeField.tsx +0 -148
- package/template/apps/web/src/components/platform-fields/JsonField.tsx +0 -77
- package/template/apps/web/src/components/platform-fields/LocationField.tsx +0 -164
- package/template/apps/web/src/components/platform-fields/PlatformDirectoryPicker.tsx +0 -673
- package/template/apps/web/src/components/platform-fields/ResourceReferenceField.tsx +0 -67
- package/template/apps/web/src/components/platform-fields/RichTextField.tsx +0 -196
- package/template/apps/web/src/components/platform-fields/SignatureField.tsx +0 -315
- package/template/apps/web/src/components/platform-fields/SubtableField.tsx +0 -553
- package/template/apps/web/src/components/platform-fields/address-value.ts +0 -80
- package/template/apps/web/src/components/platform-fields/cascade-value.ts +0 -66
- package/template/apps/web/src/components/platform-fields/directory-value.ts +0 -53
- package/template/apps/web/src/components/platform-fields/field-form-codec.ts +0 -98
- package/template/apps/web/src/components/platform-fields/location-value.ts +0 -87
- package/template/apps/web/src/components/platform-fields/resource-query.ts +0 -131
- package/template/apps/web/src/components/platform-fields/rich-text-value.ts +0 -59
- package/template/apps/web/src/components/platform-fields/subtable-value.ts +0 -187
- package/template/apps/web/src/components/resource/GeneratedResourceCrud.tsx +0 -1184
- package/template/apps/web/src/components/resource/ResourceBatchActions.tsx +0 -326
- package/template/apps/web/src/components/resource/StandardResourcePages.tsx +0 -392
- package/template/apps/web/src/components/resource/SurfaceFields.tsx +0 -915
- package/template/apps/web/src/components/resource/generated-resource-definition.ts +0 -18
- package/template/apps/web/src/components/resource/resource-import.ts +0 -205
- package/template/apps/web/src/data-provider.ts +0 -72
- package/template/apps/web/src/platform-client.ts +0 -708
- package/template/apps/web/src/runtime-meta.ts +0 -75
- package/template/apps/web/src/runtime.tsx +0 -227
- package/template/apps/web/src/styles.css +0 -1941
- package/template/apps/web/test/address-field.test.ts +0 -66
- package/template/apps/web/test/cascade-value.test.ts +0 -68
- package/template/apps/web/test/directory-value.test.ts +0 -55
- package/template/apps/web/test/field-bounds.test.ts +0 -17
- package/template/apps/web/test/field-form-codec.test.ts +0 -85
- package/template/apps/web/test/location-field.test.ts +0 -83
- package/template/apps/web/test/resource-import.test.ts +0 -143
- package/template/apps/web/test/resource-query.test.ts +0 -144
- package/template/apps/web/test/rich-json-field.test.ts +0 -53
- package/template/apps/web/test/signature-serial-field.test.ts +0 -40
- 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
|
-
}
|