@skopon-cool/form-sdk 0.6.2 → 0.6.4

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 (37) hide show
  1. package/dist/adapter/a2uiAdapter.d.ts +1 -1
  2. package/dist/adapter/a2uiAdapter.d.ts.map +1 -1
  3. package/dist/adapter/formAssetOptions.d.ts +3 -0
  4. package/dist/adapter/formAssetOptions.d.ts.map +1 -0
  5. package/dist/adapter/formSchema.d.ts.map +1 -1
  6. package/dist/adapter/resolveSurface.d.ts +1 -1
  7. package/dist/adapter/resolveSurface.d.ts.map +1 -1
  8. package/dist/catalog/a2uiCustomCatalog.d.ts.map +1 -1
  9. package/dist/components/AskUserFormCard.d.ts +2 -0
  10. package/dist/components/AskUserFormCard.d.ts.map +1 -1
  11. package/dist/form-sdk.css +1 -1
  12. package/dist/index.d.ts +1 -1
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +2018 -1797
  15. package/dist/submit/buildAnswerAgentBody.d.ts.map +1 -1
  16. package/dist/submit/intersectPayloadBlocksWithForm.d.ts +11 -2
  17. package/dist/submit/intersectPayloadBlocksWithForm.d.ts.map +1 -1
  18. package/dist/types/index.d.ts +39 -1
  19. package/dist/types/index.d.ts.map +1 -1
  20. package/package.json +1 -1
  21. package/src/adapter/a2uiAdapter.test.ts +16 -0
  22. package/src/adapter/a2uiAdapter.ts +66 -2
  23. package/src/adapter/formAssetOptions.ts +19 -0
  24. package/src/adapter/formSchema.ts +60 -0
  25. package/src/adapter/resolveSurface.ts +4 -1
  26. package/src/catalog/a2uiCustomCatalog.tsx +216 -13
  27. package/src/catalog/fileUploadPreview.test.tsx +73 -0
  28. package/src/catalog/moduleTabs.test.tsx +59 -0
  29. package/src/components/AskUserFormCard.tsx +28 -9
  30. package/src/components/AskUserFormCard.upload.test.tsx +66 -0
  31. package/src/icons/FilePlaceholderIcon.tsx +2 -2
  32. package/src/index.ts +2 -0
  33. package/src/styles/index.css +295 -0
  34. package/src/submit/buildAnswerAgentBody.ts +2 -0
  35. package/src/submit/intersectPayloadBlocksWithForm.ts +52 -3
  36. package/src/submit/submit.test.ts +54 -0
  37. package/src/types/index.ts +41 -0
@@ -1 +1 @@
1
- {"version":3,"file":"buildAnswerAgentBody.d.ts","sourceRoot":"","sources":["../../src/submit/buildAnswerAgentBody.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAChD,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,kCAAkC,CAAA;AAEzC,MAAM,WAAW,yBAAyB;IACxC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAClC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,uBAAuB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACvC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B;AAmBD,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,yBAAyB,CAAA;IAClC,OAAO,EAAE,OAAO,CAAA;IAChB,IAAI,CAAC,EAAE,uBAAuB,GAAG,UAAU,GAAG,IAAI,CAAA;IAClD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAChC;AAED,4DAA4D;AAC5D,wBAAgB,oBAAoB,CAAC,EACnC,OAAO,EACP,OAAO,EACP,IAAI,EACJ,MAAM,GACP,EAAE,2BAA2B,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAevD;AAED,iDAAiD;AACjD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,IAAI,CAqBpF;AAED,iCAAiC;AACjC,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,yBAAyB,GACjC,MAAM,GAAG,IAAI,CAQf"}
1
+ {"version":3,"file":"buildAnswerAgentBody.d.ts","sourceRoot":"","sources":["../../src/submit/buildAnswerAgentBody.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAChD,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,kCAAkC,CAAA;AAEzC,MAAM,WAAW,yBAAyB;IACxC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAClC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,uBAAuB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACvC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B;AAqBD,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,yBAAyB,CAAA;IAClC,OAAO,EAAE,OAAO,CAAA;IAChB,IAAI,CAAC,EAAE,uBAAuB,GAAG,UAAU,GAAG,IAAI,CAAA;IAClD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAChC;AAED,4DAA4D;AAC5D,wBAAgB,oBAAoB,CAAC,EACnC,OAAO,EACP,OAAO,EACP,IAAI,EACJ,MAAM,GACP,EAAE,2BAA2B,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAevD;AAED,iDAAiD;AACjD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,IAAI,CAqBpF;AAED,iCAAiC;AACjC,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,yBAAyB,GACjC,MAAM,GAAG,IAAI,CAQf"}
@@ -1,5 +1,6 @@
1
1
  import type { FormBlock, FormSchema } from '../types/index';
2
- export type PayloadBlocksDefinition = Pick<FormSchema, 'title' | 'description' | 'blocks'> & {
2
+ export type PayloadBlocksDefinition = Pick<FormSchema, 'title' | 'description' | 'modules' | 'blocks'> & {
3
+ schema?: 'skopon.material-form/v2';
3
4
  /**
4
5
  * ask 原始 blocks(normalize 前)。交集合并按此键集覆盖 form,
5
6
  * 避免 normalize 填入的空默认值误盖表单样式。
@@ -13,6 +14,14 @@ export interface PayloadBlocksIntersection {
13
14
  renderBlocks: FormBlock[];
14
15
  title: string;
15
16
  description: string;
17
+ modules?: FormSchema['modules'];
18
+ }
19
+ export interface IntersectPayloadBlocksOptions {
20
+ /**
21
+ * snapshot:消息快照中的显式配置优先(兼容旧行为);
22
+ * latest:最新表单负责布局/文案/校验,只保留快照里的填写与审核运行态。
23
+ */
24
+ definitionPolicy?: 'snapshot' | 'latest';
16
25
  }
17
26
  /** 解析 ask_user payload 为 blocksJson 形(title / description / blocks) */
18
27
  export declare function parsePayloadBlocksJson(payload: unknown): PayloadBlocksDefinition | null;
@@ -20,7 +29,7 @@ export declare function parsePayloadBlocksJson(payload: unknown): PayloadBlocksD
20
29
  * payload.blocks 与 vt_forms 按 input 块 name 取交集用于渲染;
21
30
  * payload 中 form 不存在的块归入 extraBlocks(不渲染,提交时写入 curl)。
22
31
  */
23
- export declare function intersectPayloadBlocksWithForm(payloadDef: PayloadBlocksDefinition, formDefinition: FormSchema | undefined): PayloadBlocksIntersection;
32
+ export declare function intersectPayloadBlocksWithForm(payloadDef: PayloadBlocksDefinition, formDefinition: FormSchema | undefined, options?: IntersectPayloadBlocksOptions): PayloadBlocksIntersection;
24
33
  /** 从 extraBlocks 提取提交值(优先 defaultValue) */
25
34
  export declare function extractExtraBlockValues(extraBlocks: FormBlock[]): Record<string, unknown>;
26
35
  /** payload 是否含至少一个具 name 的 input 块(可用于卡片 fallback) */
@@ -1 +1 @@
1
- {"version":3,"file":"intersectPayloadBlocksWithForm.d.ts","sourceRoot":"","sources":["../../src/submit/intersectPayloadBlocksWithForm.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAG3D,MAAM,MAAM,uBAAuB,GAAG,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,aAAa,GAAG,QAAQ,CAAC,GAAG;IAC3F;;;OAGG;IACH,SAAS,CAAC,EAAE,SAAS,EAAE,CAAA;CACxB,CAAA;AAED,MAAM,WAAW,yBAAyB;IACxC,aAAa,EAAE,SAAS,EAAE,CAAA;IAC1B,WAAW,EAAE,SAAS,EAAE,CAAA;IACxB,gEAAgE;IAChE,YAAY,EAAE,SAAS,EAAE,CAAA;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;CACpB;AA+ED,uEAAuE;AACvE,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,uBAAuB,GAAG,IAAI,CAmBvF;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAC5C,UAAU,EAAE,uBAAuB,EACnC,cAAc,EAAE,UAAU,GAAG,SAAS,GACrC,yBAAyB,CA+B3B;AA+BD,2CAA2C;AAC3C,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASzF;AAED,sDAAsD;AACtD,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,uBAAuB,GAAG,OAAO,CAOlF;AAED,yEAAyE;AACzE,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,uBAAuB,GAAG,SAAS,EAAE,CAQ3F;AAED,4DAA4D;AAC5D,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,uBAAuB,GAAG,MAAM,EAAE,CASvF;AAED,6DAA6D;AAC7D,wBAAgB,2BAA2B,CACzC,UAAU,EAAE,uBAAuB,GAClC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASzB"}
1
+ {"version":3,"file":"intersectPayloadBlocksWithForm.d.ts","sourceRoot":"","sources":["../../src/submit/intersectPayloadBlocksWithForm.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAG3D,MAAM,MAAM,uBAAuB,GAAG,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,aAAa,GAAG,SAAS,GAAG,QAAQ,CAAC,GAAG;IACvG,MAAM,CAAC,EAAE,yBAAyB,CAAA;IAClC;;;OAGG;IACH,SAAS,CAAC,EAAE,SAAS,EAAE,CAAA;CACxB,CAAA;AAED,MAAM,WAAW,yBAAyB;IACxC,aAAa,EAAE,SAAS,EAAE,CAAA;IAC1B,WAAW,EAAE,SAAS,EAAE,CAAA;IACxB,gEAAgE;IAChE,YAAY,EAAE,SAAS,EAAE,CAAA;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAA;CAChC;AAUD,MAAM,WAAW,6BAA6B;IAC5C;;;OAGG;IACH,gBAAgB,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAA;CACzC;AAiGD,uEAAuE;AACvE,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,uBAAuB,GAAG,IAAI,CAsBvF;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAC5C,UAAU,EAAE,uBAAuB,EACnC,cAAc,EAAE,UAAU,GAAG,SAAS,EACtC,OAAO,CAAC,EAAE,6BAA6B,GACtC,yBAAyB,CAwC3B;AA+BD,2CAA2C;AAC3C,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASzF;AAED,sDAAsD;AACtD,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,uBAAuB,GAAG,OAAO,CAOlF;AAED,yEAAyE;AACzE,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,uBAAuB,GAAG,SAAS,EAAE,CAQ3F;AAED,4DAA4D;AAC5D,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,uBAAuB,GAAG,MAAM,EAAE,CASvF;AAED,6DAA6D;AAC7D,wBAAgB,2BAA2B,CACzC,UAAU,EAAE,uBAAuB,GAClC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASzB"}
@@ -4,7 +4,15 @@
4
4
  export type A2uiBinding<T> = T | {
5
5
  path: string;
6
6
  };
7
- export type A2uiComponentName = 'Column' | 'Row' | 'Text' | 'Image' | 'Video' | 'AudioPlayer' | 'TextField' | 'CheckBox' | 'ChoicePicker' | 'DateTimeInput' | 'FileUpload' | 'SkoponMedia' | 'SkoponWeb' | 'SkoponSelect' | 'SkoponResumeSelect' | 'SkoponCaseSelect';
7
+ export type A2uiComponentName = 'Column' | 'Row' | 'Text' | 'Image' | 'Video' | 'AudioPlayer' | 'TextField' | 'CheckBox' | 'ChoicePicker' | 'DateTimeInput' | 'FileUpload' | 'SkoponMedia' | 'SkoponWeb' | 'SkoponSelect' | 'SkoponResumeSelect' | 'SkoponCaseSelect' | 'SkoponModulePanel';
8
+ /** 表单分组模块。运行时以 Tab 展示,要求与示例统一放在模块底部。 */
9
+ export interface FormModule {
10
+ id: string;
11
+ label: string;
12
+ description?: string;
13
+ reviewCriteria?: string;
14
+ exampleUrls?: string[];
15
+ }
8
16
  export interface A2uiComponentNode {
9
17
  id: string;
10
18
  component: A2uiComponentName | string;
@@ -31,6 +39,13 @@ export interface FormBlockOption {
31
39
  value: string;
32
40
  label: string;
33
41
  }
42
+ export interface FormAssetOption {
43
+ assetId: string;
44
+ url: string;
45
+ previewUrl?: string;
46
+ label: string;
47
+ assetType?: string;
48
+ }
34
49
  export type FormConditionOperator = 'eq' | 'ne' | 'empty' | 'notEmpty';
35
50
  export interface FormBlockCondition {
36
51
  fieldName: string;
@@ -99,6 +114,25 @@ export interface FormBlock {
99
114
  filePlaceholderIcon?: FormFilePlaceholderIcon;
100
115
  fileMinCount?: number;
101
116
  fileMaxCount?: number;
117
+ /** 上传素材的示例图,仅展示,不参与提交。 */
118
+ fileExampleUrls?: string[];
119
+ /** 制作模板的逐字段审核标准;由工作流读取,不能使用提交值覆盖。 */
120
+ fileReviewCriteria?: string;
121
+ /** 是否需要由工作流审核上传内容;素材库已审核素材可以关闭。 */
122
+ fileReviewRequired?: boolean;
123
+ /** 物料采集来源模式,由 skopon-admin 环节配置。 */
124
+ fileSourceMode?: 'upload_required' | 'upload_or_asset' | 'asset_only';
125
+ /** 通用收集流从 Footage 为当前素材位查询的候选;仅提交选中的文件 URL。 */
126
+ fileAssetOptions?: FormAssetOption[];
127
+ /** 对应 Footage 同步素材位的限定 key。 */
128
+ assetSlotKey?: string;
129
+ assetType?: 'image' | 'video' | 'audio' | 'text';
130
+ /** 运行时素材审核状态;用于返工表单回显,不作为用户提交值。 */
131
+ fileReviewStatus?: 'passed' | 'failed';
132
+ /** 运行时素材审核说明;failed 时通常为不合格原因。 */
133
+ fileReviewMessage?: string;
134
+ /** 审核未通过的历史文件,仅作错误态回显,不计入有效提交。 */
135
+ fileRejectedUrls?: string[];
102
136
  defaultValue?: string | string[] | boolean;
103
137
  /** 派生 JSON Schema 时写入 property.$comment */
104
138
  jsonSchemaDescription?: string;
@@ -129,10 +163,13 @@ export interface FormBlock {
129
163
  /** 案例单选:列表筛选条件(持久化进 block json) */
130
164
  caseFilter?: FormCaseFilter;
131
165
  condition?: FormBlockCondition;
166
+ /** 所属模块;命中 FormSchema.modules.id 时在对应 Tab 中展示。 */
167
+ moduleId?: string;
132
168
  }
133
169
  export interface FormSchema {
134
170
  title?: string;
135
171
  description?: string;
172
+ modules?: FormModule[];
136
173
  blocks: FormBlock[];
137
174
  jsonSchema: FormJsonSchema;
138
175
  }
@@ -146,6 +183,7 @@ export declare function supportsDefaultValue(type: FormBlockType): boolean;
146
183
  export interface FormDefinitionPayload {
147
184
  title?: string;
148
185
  description?: string;
186
+ modules?: FormModule[];
149
187
  blocks?: FormBlock[];
150
188
  a2ui?: A2uiSurfaceDoc;
151
189
  json_schema?: FormJsonSchema;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.6.2",
6
+ "version": "0.6.4",
7
7
  "description": "Skopon form rendering SDK (A2UI + form_definition) with submit helpers",
8
8
  "type": "module",
9
9
  "sideEffects": [
@@ -44,6 +44,22 @@ function makeDefinition(): Pick<FormSchema, 'title' | 'description' | 'blocks'>
44
44
  }
45
45
 
46
46
  describe('a2uiAdapter blocks <-> surface', () => {
47
+ it('preserves material upload examples and review criteria through normalization and A2UI', () => {
48
+ const definition = normalizeFormDefinition({ blocks: [{
49
+ id: 'material', type: 'file', name: 'image01', help: '上传人物',
50
+ fileExampleUrls: [' https://cdn.test/example.jpg ', 'javascript:alert(1)', 'https://cdn.test/example.jpg'],
51
+ fileReviewCriteria: ' 五官清晰 ',
52
+ fileReviewStatus: 'failed', fileReviewMessage: ' 面部模糊 ',
53
+ fileRejectedUrls: ['https://cdn.test/rejected.jpg'],
54
+ }] })
55
+ const back = a2uiToBlocks(blocksToA2ui(definition))
56
+ expect(back.blocks[0]).toMatchObject({
57
+ name: 'image01', help: '上传人物', fileReviewCriteria: '五官清晰',
58
+ fileExampleUrls: ['https://cdn.test/example.jpg'],
59
+ fileReviewStatus: 'failed', fileReviewMessage: '面部模糊',
60
+ fileRejectedUrls: ['https://cdn.test/rejected.jpg'],
61
+ })
62
+ })
47
63
  it('blocksToA2ui builds a Column root referencing all components', () => {
48
64
  const doc = blocksToA2ui(makeDefinition(), { styleId: 'theme-a' })
49
65
  const root = doc.components.find((c) => c.id === 'root')
@@ -1,3 +1,4 @@
1
+ import { normalizeAssetOptions } from './formAssetOptions'
1
2
  import type {
2
3
  A2uiComponentNode,
3
4
  A2uiSurfaceDoc,
@@ -276,6 +277,17 @@ function blockToComponent(block: FormBlock): {
276
277
  id,
277
278
  component: 'FileUpload',
278
279
  label,
280
+ help: block.help ?? '',
281
+ fileExampleUrls: block.fileExampleUrls ?? [],
282
+ fileReviewCriteria: block.fileReviewCriteria ?? '',
283
+ fileReviewRequired: block.fileReviewRequired !== false,
284
+ fileSourceMode: block.fileSourceMode,
285
+ fileAssetOptions: block.fileAssetOptions ?? [],
286
+ assetSlotKey: block.assetSlotKey,
287
+ assetType: block.assetType,
288
+ fileReviewStatus: block.fileReviewStatus,
289
+ fileReviewMessage: block.fileReviewMessage ?? '',
290
+ fileRejectedUrls: block.fileRejectedUrls ?? [],
279
291
  accept: (block.fileAcceptExtensions ?? []).join(','),
280
292
  fileAcceptTypes: block.fileAcceptTypes ?? [],
281
293
  filePlaceholderIcon: block.filePlaceholderIcon ?? 'document',
@@ -307,12 +319,15 @@ export function isA2uiSurfaceEmpty(doc: A2uiSurfaceDoc | null | undefined): bool
307
319
 
308
320
  /** FormBlock[] -> A2UI surface 文档 */
309
321
  export function blocksToA2ui(
310
- definition: Pick<FormSchema, 'title' | 'description' | 'blocks'>,
322
+ definition: Pick<FormSchema, 'title' | 'description' | 'modules' | 'blocks'>,
311
323
  options?: BlocksToA2uiOptions,
312
324
  ): A2uiSurfaceDoc {
313
325
  const components: A2uiComponentNode[] = []
314
326
  const childIds: string[] = []
315
327
  const dataModel: Record<string, unknown> = {}
328
+ const modules = definition.modules ?? []
329
+ const moduleById = new Map(modules.map((module) => [module.id, module]))
330
+ const moduleChildIds = new Map(modules.map((module) => [module.id, [] as string[]]))
316
331
 
317
332
  const includeHeader = options?.includeHeader !== false
318
333
  const title = (definition.title ?? '').trim()
@@ -332,8 +347,40 @@ export function blocksToA2ui(
332
347
  // hidden 等无节点块仍可写入 dataModel,保证「不展示仍提交」
333
348
  if (dataKey) dataModel[dataKey] = dataValue
334
349
  if (!node) continue
350
+ const moduleId = block.moduleId?.trim()
351
+ if (moduleId && moduleById.has(moduleId) && node.component === 'FileUpload') {
352
+ // 分组表单把公共说明集中放在 Tab 底部,避免每个上传位重复拉长页面。
353
+ node.fileExampleUrls = []
354
+ node.fileReviewCriteria = ''
355
+ node.compact = true
356
+ }
335
357
  components.push(node)
336
- childIds.push(node.id)
358
+ if (moduleId && moduleChildIds.has(moduleId)) {
359
+ moduleChildIds.get(moduleId)!.push(node.id)
360
+ } else {
361
+ childIds.push(node.id)
362
+ }
363
+ }
364
+
365
+ const tabs = modules.flatMap((module) => {
366
+ const children = moduleChildIds.get(module.id) ?? []
367
+ if (children.length === 0) return []
368
+ const panelId = `__module_panel_${module.id}`
369
+ components.push({
370
+ id: panelId,
371
+ component: 'SkoponModulePanel',
372
+ children,
373
+ single: children.length === 1,
374
+ description: module.description ?? '',
375
+ requirementsTitle: `${module.label.replace(/(.*?)|\(.*?\)/g, '').trim()}素材要求`,
376
+ reviewCriteria: module.reviewCriteria ?? '',
377
+ exampleUrls: module.exampleUrls ?? [],
378
+ })
379
+ return [{ title: module.label, child: panelId }]
380
+ })
381
+ if (tabs.length > 0) {
382
+ components.push({ id: '__modules__', component: 'Tabs', tabs })
383
+ childIds.push('__modules__')
337
384
  }
338
385
 
339
386
  components.unshift({ id: ROOT_ID, component: 'Column', children: childIds })
@@ -448,6 +495,23 @@ function componentToBlock(node: A2uiComponentNode): FormBlock | null {
448
495
  case 'FileUpload': {
449
496
  const accept = asLiteral(node.accept) ?? ''
450
497
  const block: FormBlock = { ...base('file'), name }
498
+ block.help = asLiteral(node.help)
499
+ block.fileReviewCriteria = asLiteral(node.fileReviewCriteria)
500
+ block.fileReviewRequired = node.fileReviewRequired !== false
501
+ if (node.fileSourceMode === 'upload_required' || node.fileSourceMode === 'upload_or_asset' || node.fileSourceMode === 'asset_only') block.fileSourceMode = node.fileSourceMode
502
+ block.fileAssetOptions = normalizeAssetOptions(node.fileAssetOptions)
503
+ block.assetSlotKey = asLiteral(node.assetSlotKey)
504
+ if (node.assetType === 'image' || node.assetType === 'video' || node.assetType === 'audio' || node.assetType === 'text') block.assetType = node.assetType
505
+ if (node.fileReviewStatus === 'passed' || node.fileReviewStatus === 'failed') {
506
+ block.fileReviewStatus = node.fileReviewStatus
507
+ }
508
+ block.fileReviewMessage = asLiteral(node.fileReviewMessage)
509
+ if (Array.isArray(node.fileRejectedUrls)) {
510
+ block.fileRejectedUrls = node.fileRejectedUrls.filter((url): url is string => typeof url === 'string')
511
+ }
512
+ if (Array.isArray(node.fileExampleUrls)) {
513
+ block.fileExampleUrls = node.fileExampleUrls.filter((url): url is string => typeof url === 'string')
514
+ }
451
515
  if (accept) block.fileAcceptExtensions = accept.split(',').map((s) => s.trim()).filter(Boolean)
452
516
  if (Array.isArray(node.fileAcceptTypes)) {
453
517
  block.fileAcceptTypes = node.fileAcceptTypes.map(String)
@@ -0,0 +1,19 @@
1
+ import type { FormAssetOption } from '../types/index'
2
+
3
+ export function normalizeAssetOptions(raw: unknown): FormAssetOption[] {
4
+ if (!Array.isArray(raw)) return []
5
+ const seen = new Set<string>()
6
+ return raw.slice(0, 100).flatMap((item) => {
7
+ if (!item || typeof item !== 'object') return []
8
+ const assetId = String(item.assetId ?? '').trim()
9
+ const url = typeof item.url === 'string' ? item.url.trim() : ''
10
+ if (!assetId || seen.has(assetId) || !/^https?:\/\//i.test(url)) return []
11
+ seen.add(assetId)
12
+ return [{
13
+ assetId, url,
14
+ label: typeof item.label === 'string' ? item.label : `素材 ${assetId}`,
15
+ previewUrl: typeof item.previewUrl === 'string' && /^https?:\/\//i.test(item.previewUrl) ? item.previewUrl : undefined,
16
+ assetType: typeof item.assetType === 'string' ? item.assetType : undefined,
17
+ }]
18
+ })
19
+ }
@@ -5,6 +5,7 @@ import type {
5
5
  FormContentFilter,
6
6
  FormResumeFilter,
7
7
  FormJsonSchema,
8
+ FormModule,
8
9
  FormSchema,
9
10
  } from '../types/index'
10
11
  import {
@@ -25,6 +26,7 @@ import {
25
26
  } from './formMedia'
26
27
  import { FORM_WEB_DEFAULT_HEIGHT, normalizeWebHeight } from './formWeb'
27
28
  import { hasRenderableFormOptions, normalizeFormOptions } from './formOptions'
29
+ import { normalizeAssetOptions } from './formAssetOptions'
28
30
 
29
31
  const DEFAULT_MEDIA_URL_MAX = 10
30
32
 
@@ -194,6 +196,7 @@ function normalizeBlock(raw: FormBlock): FormBlock {
194
196
  return {
195
197
  id: migrated.id?.trim() || generateId('block-'),
196
198
  type,
199
+ moduleId: migrated.moduleId?.trim() || undefined,
197
200
  name: migrated.name?.trim() || undefined,
198
201
  label: migrated.label ?? '',
199
202
  placeholder: migrated.placeholder ?? '',
@@ -213,6 +216,30 @@ function normalizeBlock(raw: FormBlock): FormBlock {
213
216
  filePlaceholderIcon: normalizeFilePlaceholderIcon(migrated.filePlaceholderIcon),
214
217
  fileMinCount: type === 'file' ? normalizeFileUploadCount(migrated.fileMinCount, 1) : undefined,
215
218
  fileMaxCount: type === 'file' ? normalizeFileUploadCount(migrated.fileMaxCount, 1) : undefined,
219
+ fileExampleUrls: type === 'file' && Array.isArray(migrated.fileExampleUrls)
220
+ ? [...new Set(migrated.fileExampleUrls.filter((url): url is string =>
221
+ typeof url === 'string' && /^https?:\/\//i.test(url.trim()),
222
+ ).map((url) => url.trim()))]
223
+ : undefined,
224
+ fileReviewCriteria: type === 'file' ? migrated.fileReviewCriteria?.trim() ?? '' : undefined,
225
+ fileReviewRequired: type === 'file' ? migrated.fileReviewRequired !== false : undefined,
226
+ fileSourceMode: type === 'file' && ['upload_required', 'upload_or_asset', 'asset_only'].includes(String(migrated.fileSourceMode))
227
+ ? migrated.fileSourceMode
228
+ : undefined,
229
+ fileAssetOptions: type === 'file' ? normalizeAssetOptions(migrated.fileAssetOptions) : undefined,
230
+ assetSlotKey: type === 'file' ? migrated.assetSlotKey?.trim() || undefined : undefined,
231
+ assetType: type === 'file' && ['image', 'video', 'audio', 'text'].includes(String(migrated.assetType))
232
+ ? migrated.assetType
233
+ : undefined,
234
+ fileReviewStatus: type === 'file' && (migrated.fileReviewStatus === 'passed' || migrated.fileReviewStatus === 'failed')
235
+ ? migrated.fileReviewStatus
236
+ : undefined,
237
+ fileReviewMessage: type === 'file' ? migrated.fileReviewMessage?.trim() ?? '' : undefined,
238
+ fileRejectedUrls: type === 'file' && Array.isArray(migrated.fileRejectedUrls)
239
+ ? [...new Set(migrated.fileRejectedUrls.filter((url): url is string =>
240
+ typeof url === 'string' && /^https?:\/\//i.test(url.trim()),
241
+ ).map((url) => url.trim()))]
242
+ : undefined,
216
243
  defaultValue: normalizeDefaultValue(type, migrated.defaultValue),
217
244
  jsonSchemaDescription: migrated.jsonSchemaDescription?.trim() ?? '',
218
245
  hidden: type === 'text' ? migrated.hidden === true : undefined,
@@ -432,19 +459,52 @@ export function syncFormDefinition(definition: FormSchema): FormSchema {
432
459
  return {
433
460
  title,
434
461
  description,
462
+ modules: definition.modules,
435
463
  blocks: definition.blocks,
436
464
  jsonSchema: blocksToJsonSchema(definition.blocks, title, description),
437
465
  }
438
466
  }
439
467
 
468
+ function normalizeModules(raw: FormModule[] | undefined): FormModule[] | undefined {
469
+ if (!Array.isArray(raw)) return undefined
470
+ const ids = new Set<string>()
471
+ const modules: FormModule[] = []
472
+ for (const item of raw) {
473
+ if (!item || typeof item !== 'object') continue
474
+ const id = item.id?.trim()
475
+ const label = item.label?.trim()
476
+ if (!id || !label || ids.has(id)) continue
477
+ ids.add(id)
478
+ const exampleUrls = Array.isArray(item.exampleUrls)
479
+ ? [...new Set(item.exampleUrls
480
+ .filter((url): url is string => typeof url === 'string' && /^https?:\/\//i.test(url.trim()))
481
+ .map((url) => url.trim()))]
482
+ : undefined
483
+ modules.push({
484
+ id,
485
+ label,
486
+ description: item.description?.trim() || undefined,
487
+ reviewCriteria: item.reviewCriteria?.trim() || undefined,
488
+ exampleUrls,
489
+ })
490
+ }
491
+ return modules.length > 0 ? modules : undefined
492
+ }
493
+
440
494
  export function normalizeFormDefinition(raw: FormSchema | undefined): FormSchema {
441
495
  if (!raw || !Array.isArray(raw.blocks)) {
442
496
  return syncFormDefinition({ title: '', description: '', blocks: [], jsonSchema: {} })
443
497
  }
444
498
  const blocks = raw.blocks.map(normalizeBlock)
499
+ const modules = normalizeModules(raw.modules)
500
+ const moduleIds = new Set(modules?.map((item) => item.id) ?? [])
501
+ for (const block of blocks) {
502
+ if (block.moduleId && !moduleIds.has(block.moduleId)) block.moduleId = undefined
503
+ }
445
504
  return syncFormDefinition({
446
505
  title: typeof raw.title === 'string' ? raw.title : '',
447
506
  description: typeof raw.description === 'string' ? raw.description : '',
507
+ modules,
448
508
  blocks,
449
509
  jsonSchema: {},
450
510
  })
@@ -26,6 +26,7 @@ export function resolveSurfaceFromFormDefinition(
26
26
  const normalized = normalizeFormDefinition({
27
27
  title: typeof payload.title === 'string' ? payload.title : '',
28
28
  description: typeof payload.description === 'string' ? payload.description : '',
29
+ modules: Array.isArray(payload.modules) ? payload.modules : undefined,
29
30
  blocks,
30
31
  jsonSchema: normalizeJsonSchema(payload.jsonSchema ?? payload.json_schema),
31
32
  })
@@ -34,7 +35,7 @@ export function resolveSurfaceFromFormDefinition(
34
35
  }
35
36
 
36
37
  export function buildAskUserSurface(
37
- formDef: Pick<FormSchema, 'title' | 'description'>,
38
+ formDef: Pick<FormSchema, 'title' | 'description' | 'modules'>,
38
39
  matchedBlocks: FormBlock[],
39
40
  options?: BlocksToA2uiOptions,
40
41
  ): A2uiSurfaceDoc {
@@ -42,6 +43,7 @@ export function buildAskUserSurface(
42
43
  {
43
44
  title: formDef.title,
44
45
  description: formDef.description,
46
+ modules: formDef.modules,
45
47
  blocks: matchedBlocks,
46
48
  },
47
49
  options,
@@ -60,6 +62,7 @@ export function mapFormDefinitionFromDto(raw: unknown): FormSchema | undefined {
60
62
  return normalizeFormDefinition({
61
63
  title: typeof obj.title === 'string' ? obj.title : '',
62
64
  description: typeof obj.description === 'string' ? obj.description : '',
65
+ modules: Array.isArray(obj.modules) ? obj.modules as FormSchema['modules'] : undefined,
63
66
  blocks: Array.isArray(obj.blocks) ? (obj.blocks as FormSchema['blocks']) : [],
64
67
  jsonSchema: normalizeJsonSchema(obj.jsonSchema ?? obj.json_schema),
65
68
  })