@skopon-cool/form-sdk 0.6.3 → 0.6.5

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 (43) 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/catalog/materialUploadContext.d.ts +24 -0
  10. package/dist/catalog/materialUploadContext.d.ts.map +1 -0
  11. package/dist/components/AskUserFormCard.d.ts +5 -0
  12. package/dist/components/AskUserFormCard.d.ts.map +1 -1
  13. package/dist/components/SkoponFormRenderer.d.ts +3 -0
  14. package/dist/components/SkoponFormRenderer.d.ts.map +1 -1
  15. package/dist/form-sdk.css +1 -1
  16. package/dist/index.d.ts +1 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +2170 -1928
  19. package/dist/submit/buildAnswerAgentBody.d.ts.map +1 -1
  20. package/dist/submit/intersectPayloadBlocksWithForm.d.ts +11 -2
  21. package/dist/submit/intersectPayloadBlocksWithForm.d.ts.map +1 -1
  22. package/dist/types/index.d.ts +35 -1
  23. package/dist/types/index.d.ts.map +1 -1
  24. package/package.json +1 -1
  25. package/src/adapter/a2uiAdapter.test.ts +4 -0
  26. package/src/adapter/a2uiAdapter.ts +58 -2
  27. package/src/adapter/formAssetOptions.ts +19 -0
  28. package/src/adapter/formSchema.ts +54 -0
  29. package/src/adapter/resolveSurface.ts +4 -1
  30. package/src/catalog/a2uiCustomCatalog.tsx +296 -46
  31. package/src/catalog/fileUploadPreview.test.tsx +77 -11
  32. package/src/catalog/materialUploadContext.tsx +43 -0
  33. package/src/catalog/moduleTabs.test.tsx +59 -0
  34. package/src/components/AskUserFormCard.tsx +33 -9
  35. package/src/components/AskUserFormCard.upload.test.tsx +66 -0
  36. package/src/components/SkoponFormRenderer.tsx +6 -0
  37. package/src/icons/FilePlaceholderIcon.tsx +2 -2
  38. package/src/index.ts +2 -0
  39. package/src/styles/index.css +295 -0
  40. package/src/submit/buildAnswerAgentBody.ts +2 -0
  41. package/src/submit/intersectPayloadBlocksWithForm.ts +52 -3
  42. package/src/submit/submit.test.ts +54 -0
  43. package/src/types/index.ts +37 -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;
@@ -103,6 +118,21 @@ export interface FormBlock {
103
118
  fileExampleUrls?: string[];
104
119
  /** 制作模板的逐字段审核标准;由工作流读取,不能使用提交值覆盖。 */
105
120
  fileReviewCriteria?: string;
121
+ /** 是否需要由工作流审核上传内容;素材库已审核素材可以关闭。 */
122
+ fileReviewRequired?: boolean;
123
+ /** 物料采集来源模式,由 skopon-admin 环节配置。 */
124
+ fileSourceMode?: 'upload_required' | 'upload_or_asset' | 'asset_only';
125
+ /** 通用收集流从 Footage 为当前素材位查询的候选;提交选中的素材 ID。 */
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[];
106
136
  defaultValue?: string | string[] | boolean;
107
137
  /** 派生 JSON Schema 时写入 property.$comment */
108
138
  jsonSchemaDescription?: string;
@@ -133,10 +163,13 @@ export interface FormBlock {
133
163
  /** 案例单选:列表筛选条件(持久化进 block json) */
134
164
  caseFilter?: FormCaseFilter;
135
165
  condition?: FormBlockCondition;
166
+ /** 所属模块;命中 FormSchema.modules.id 时在对应 Tab 中展示。 */
167
+ moduleId?: string;
136
168
  }
137
169
  export interface FormSchema {
138
170
  title?: string;
139
171
  description?: string;
172
+ modules?: FormModule[];
140
173
  blocks: FormBlock[];
141
174
  jsonSchema: FormJsonSchema;
142
175
  }
@@ -150,6 +183,7 @@ export declare function supportsDefaultValue(type: FormBlockType): boolean;
150
183
  export interface FormDefinitionPayload {
151
184
  title?: string;
152
185
  description?: string;
186
+ modules?: FormModule[];
153
187
  blocks?: FormBlock[];
154
188
  a2ui?: A2uiSurfaceDoc;
155
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.3",
6
+ "version": "0.6.5",
7
7
  "description": "Skopon form rendering SDK (A2UI + form_definition) with submit helpers",
8
8
  "type": "module",
9
9
  "sideEffects": [
@@ -49,11 +49,15 @@ describe('a2uiAdapter blocks <-> surface', () => {
49
49
  id: 'material', type: 'file', name: 'image01', help: '上传人物',
50
50
  fileExampleUrls: [' https://cdn.test/example.jpg ', 'javascript:alert(1)', 'https://cdn.test/example.jpg'],
51
51
  fileReviewCriteria: ' 五官清晰 ',
52
+ fileReviewStatus: 'failed', fileReviewMessage: ' 面部模糊 ',
53
+ fileRejectedUrls: ['https://cdn.test/rejected.jpg'],
52
54
  }] })
53
55
  const back = a2uiToBlocks(blocksToA2ui(definition))
54
56
  expect(back.blocks[0]).toMatchObject({
55
57
  name: 'image01', help: '上传人物', fileReviewCriteria: '五官清晰',
56
58
  fileExampleUrls: ['https://cdn.test/example.jpg'],
59
+ fileReviewStatus: 'failed', fileReviewMessage: '面部模糊',
60
+ fileRejectedUrls: ['https://cdn.test/rejected.jpg'],
57
61
  })
58
62
  })
59
63
  it('blocksToA2ui builds a Column root referencing all components', () => {
@@ -1,3 +1,4 @@
1
+ import { normalizeAssetOptions } from './formAssetOptions'
1
2
  import type {
2
3
  A2uiComponentNode,
3
4
  A2uiSurfaceDoc,
@@ -279,6 +280,14 @@ function blockToComponent(block: FormBlock): {
279
280
  help: block.help ?? '',
280
281
  fileExampleUrls: block.fileExampleUrls ?? [],
281
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 ?? [],
282
291
  accept: (block.fileAcceptExtensions ?? []).join(','),
283
292
  fileAcceptTypes: block.fileAcceptTypes ?? [],
284
293
  filePlaceholderIcon: block.filePlaceholderIcon ?? 'document',
@@ -310,12 +319,15 @@ export function isA2uiSurfaceEmpty(doc: A2uiSurfaceDoc | null | undefined): bool
310
319
 
311
320
  /** FormBlock[] -> A2UI surface 文档 */
312
321
  export function blocksToA2ui(
313
- definition: Pick<FormSchema, 'title' | 'description' | 'blocks'>,
322
+ definition: Pick<FormSchema, 'title' | 'description' | 'modules' | 'blocks'>,
314
323
  options?: BlocksToA2uiOptions,
315
324
  ): A2uiSurfaceDoc {
316
325
  const components: A2uiComponentNode[] = []
317
326
  const childIds: string[] = []
318
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[]]))
319
331
 
320
332
  const includeHeader = options?.includeHeader !== false
321
333
  const title = (definition.title ?? '').trim()
@@ -335,8 +347,40 @@ export function blocksToA2ui(
335
347
  // hidden 等无节点块仍可写入 dataModel,保证「不展示仍提交」
336
348
  if (dataKey) dataModel[dataKey] = dataValue
337
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
+ }
338
357
  components.push(node)
339
- 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__')
340
384
  }
341
385
 
342
386
  components.unshift({ id: ROOT_ID, component: 'Column', children: childIds })
@@ -453,6 +497,18 @@ function componentToBlock(node: A2uiComponentNode): FormBlock | null {
453
497
  const block: FormBlock = { ...base('file'), name }
454
498
  block.help = asLiteral(node.help)
455
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
+ }
456
512
  if (Array.isArray(node.fileExampleUrls)) {
457
513
  block.fileExampleUrls = node.fileExampleUrls.filter((url): url is string => typeof url === 'string')
458
514
  }
@@ -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 ?? '',
@@ -219,6 +222,24 @@ function normalizeBlock(raw: FormBlock): FormBlock {
219
222
  ).map((url) => url.trim()))]
220
223
  : undefined,
221
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,
222
243
  defaultValue: normalizeDefaultValue(type, migrated.defaultValue),
223
244
  jsonSchemaDescription: migrated.jsonSchemaDescription?.trim() ?? '',
224
245
  hidden: type === 'text' ? migrated.hidden === true : undefined,
@@ -438,19 +459,52 @@ export function syncFormDefinition(definition: FormSchema): FormSchema {
438
459
  return {
439
460
  title,
440
461
  description,
462
+ modules: definition.modules,
441
463
  blocks: definition.blocks,
442
464
  jsonSchema: blocksToJsonSchema(definition.blocks, title, description),
443
465
  }
444
466
  }
445
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
+
446
494
  export function normalizeFormDefinition(raw: FormSchema | undefined): FormSchema {
447
495
  if (!raw || !Array.isArray(raw.blocks)) {
448
496
  return syncFormDefinition({ title: '', description: '', blocks: [], jsonSchema: {} })
449
497
  }
450
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
+ }
451
504
  return syncFormDefinition({
452
505
  title: typeof raw.title === 'string' ? raw.title : '',
453
506
  description: typeof raw.description === 'string' ? raw.description : '',
507
+ modules,
454
508
  blocks,
455
509
  jsonSchema: {},
456
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
  })