@qingflow-tech/qingflow-cli 1.1.61-beta.5 → 1.1.61

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 (85) hide show
  1. package/README.md +3 -3
  2. package/package.json +1 -1
  3. package/pyproject.toml +1 -2
  4. package/skills/qingflow-cli/SKILL.md +2 -104
  5. package/skills/qingflow-cli/reference/builder/20-build-complete-system.md +2 -2
  6. package/skills/qingflow-cli/reference/builder/30-schema-fields.md +5 -22
  7. package/skills/qingflow-cli/reference/builder/70-portal.md +16 -37
  8. package/skills/qingflow-cli/reference/builder/reference/app-delivery-sop.md +3 -3
  9. package/skills/qingflow-cli/reference/examples/portal/portal_sections_all_types.example.json +7 -6
  10. package/src/qingflow_mcp/app_form_compat.py +0 -3
  11. package/src/qingflow_mcp/app_form_validator.py +20 -89
  12. package/src/qingflow_mcp/builder_facade/app_form.py +112 -629
  13. package/src/qingflow_mcp/builder_facade/models.py +13 -164
  14. package/src/qingflow_mcp/builder_facade/schemas/app_form/manifest.json +1 -15
  15. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/complete.json +38 -112
  16. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/address.json +8 -31
  17. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/amount.json +10 -6
  18. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/attachment.json +10 -33
  19. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/code_block.json +10 -6
  20. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/data_relation.json +18 -11
  21. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/date.json +8 -4
  22. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/datetime.json +8 -4
  23. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/department.json +10 -6
  24. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/email.json +8 -4
  25. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/link.json +8 -4
  26. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/long_text.json +8 -4
  27. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/member.json +10 -6
  28. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/multi_select.json +8 -4
  29. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/number.json +10 -6
  30. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/phone.json +8 -4
  31. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/q_linker.json +12 -8
  32. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/relation.json +15 -73
  33. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/single_choice.json +8 -4
  34. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/single_select.json +8 -4
  35. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/subtable.json +29 -90
  36. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/text.json +8 -4
  37. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/formula.json +0 -43
  38. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/summary.json +19 -27
  39. package/src/qingflow_mcp/builder_facade/service.py +72 -1143
  40. package/src/qingflow_mcp/cli/commands/builder.py +5 -114
  41. package/src/qingflow_mcp/cli/main.py +1 -34
  42. package/src/qingflow_mcp/cloud_context.py +1 -16
  43. package/src/qingflow_mcp/public_surface.py +8 -69
  44. package/src/qingflow_mcp/response_trim.py +1 -2
  45. package/src/qingflow_mcp/server.py +6 -12
  46. package/src/qingflow_mcp/server_app_builder.py +6 -41
  47. package/src/qingflow_mcp/server_app_user.py +5 -9
  48. package/src/qingflow_mcp/server_cloud.py +7 -43
  49. package/src/qingflow_mcp/solution/compiler/icon_utils.py +0 -73
  50. package/src/qingflow_mcp/solution/executor.py +2 -5
  51. package/src/qingflow_mcp/tools/ai_builder_tools.py +12 -110
  52. package/src/qingflow_mcp/tools/portal_tools.py +54 -4
  53. package/src/qingflow_mcp/tools/solution_tools.py +0 -2
  54. package/skills/qingflow-cli/reference/examples/portal/portal_apply_v1alpha1.example.json +0 -100
  55. package/src/qingflow_mcp/builder_facade/portals_schema.py +0 -397
  56. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/ai_content_classification.json +0 -146
  57. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/ai_content_extraction.json +0 -146
  58. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/ai_content_generation.json +0 -146
  59. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/ai_document_parsing.json +0 -146
  60. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/ai_image_generation.json +0 -146
  61. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/ai_image_recognition.json +0 -146
  62. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/ai_machine_translation.json +0 -146
  63. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/ai_text_summary.json +0 -146
  64. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/date_duration.json +0 -146
  65. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/embed_field.json +0 -146
  66. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/image_select.json +0 -146
  67. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/location.json +0 -146
  68. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/ocr.json +0 -146
  69. package/src/qingflow_mcp/builder_facade/schemas/app_form/v1alpha1/fields/rich_text.json +0 -146
  70. package/src/qingflow_mcp/builder_facade/schemas/portals/manifest.json +0 -59
  71. package/src/qingflow_mcp/builder_facade/schemas/portals/v1alpha1/complete.json +0 -1397
  72. package/src/qingflow_mcp/builder_facade/schemas/portals/v1alpha1/components/carousel.json +0 -193
  73. package/src/qingflow_mcp/builder_facade/schemas/portals/v1alpha1/components/chart.json +0 -643
  74. package/src/qingflow_mcp/builder_facade/schemas/portals/v1alpha1/components/favourite.json +0 -203
  75. package/src/qingflow_mcp/builder_facade/schemas/portals/v1alpha1/components/filter.json +0 -268
  76. package/src/qingflow_mcp/builder_facade/schemas/portals/v1alpha1/components/grid.json +0 -265
  77. package/src/qingflow_mcp/builder_facade/schemas/portals/v1alpha1/components/link.json +0 -131
  78. package/src/qingflow_mcp/builder_facade/schemas/portals/v1alpha1/components/task.json +0 -199
  79. package/src/qingflow_mcp/builder_facade/schemas/portals/v1alpha1/components/text.json +0 -123
  80. package/src/qingflow_mcp/builder_facade/schemas/portals/v1alpha1/components/view.json +0 -196
  81. package/src/qingflow_mcp/builder_facade/schemas/portals/v1alpha1/summary.json +0 -800
  82. package/src/qingflow_mcp/tool_catalog.py +0 -387
  83. package/src/qingflow_mcp/tool_catalog_i18n.py +0 -185
  84. package/src/qingflow_mcp/tool_policy.py +0 -197
  85. package/src/qingflow_mcp/tools/portal_writer.py +0 -59
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import re
4
4
  from enum import Enum
5
- from typing import Any, Literal, Union
5
+ from typing import Any, Union
6
6
 
7
7
  from pydantic import AliasChoices, Field, model_validator
8
8
 
@@ -2508,17 +2508,14 @@ class PortalInlineChartPatch(ChartUpsertPatch):
2508
2508
 
2509
2509
 
2510
2510
  class PortalComponentPositionPatch(StrictModel):
2511
- # 后端语义(DashSvcImpl 读/写链):position 各坐标可为 null——生产数据中筛选组件
2512
- # (type=6)的 x/y/cols/rows 原生为 NULL,读面透传 null、写链 setPosition 直存 null。
2513
- # 因此显式 null 必须原样透传(round-trip 保真);仅键缺省时才回落布局默认值。
2514
- pc_x: int | None = Field(default=0, validation_alias=AliasChoices("pc_x", "pcX", "x"))
2515
- pc_y: int | None = Field(default=0, validation_alias=AliasChoices("pc_y", "pcY", "y"))
2516
- pc_w: int | None = Field(default=12, validation_alias=AliasChoices("pc_w", "pcW", "w"))
2517
- pc_h: int | None = Field(default=8, validation_alias=AliasChoices("pc_h", "pcH", "h"))
2518
- mobile_x: int | None = Field(default=0, validation_alias=AliasChoices("mobile_x", "mobileX"))
2519
- mobile_y: int | None = Field(default=0, validation_alias=AliasChoices("mobile_y", "mobileY"))
2520
- mobile_w: int | None = Field(default=6, validation_alias=AliasChoices("mobile_w", "mobileW"))
2521
- mobile_h: int | None = Field(default=8, validation_alias=AliasChoices("mobile_h", "mobileH"))
2511
+ pc_x: int = Field(default=0, validation_alias=AliasChoices("pc_x", "pcX", "x"))
2512
+ pc_y: int = Field(default=0, validation_alias=AliasChoices("pc_y", "pcY", "y"))
2513
+ pc_w: int = Field(default=12, validation_alias=AliasChoices("pc_w", "pcW", "w"))
2514
+ pc_h: int = Field(default=8, validation_alias=AliasChoices("pc_h", "pcH", "h"))
2515
+ mobile_x: int = Field(default=0, validation_alias=AliasChoices("mobile_x", "mobileX"))
2516
+ mobile_y: int = Field(default=0, validation_alias=AliasChoices("mobile_y", "mobileY"))
2517
+ mobile_w: int = Field(default=6, validation_alias=AliasChoices("mobile_w", "mobileW"))
2518
+ mobile_h: int = Field(default=8, validation_alias=AliasChoices("mobile_h", "mobileH"))
2522
2519
  mobile_provided: bool = Field(default=False, exclude=True)
2523
2520
 
2524
2521
  @model_validator(mode="before")
@@ -2557,10 +2554,6 @@ class PortalChartRefPatch(StrictModel):
2557
2554
  app_key: str | None = None
2558
2555
  chart_id: str | None = None
2559
2556
  chart_name: str | None = None
2560
- # 引用面判别:后端有两类图表组件——轻流报表(DASH_CONTENT_TYPE_CHART=1,chart 表唯一键
2561
- # chartKey,写链 addChartInfos 按 chartKey 解析)与轻析 BI 报表(DASH_CONTENT_TYPE_BICHART=9,
2562
- # bi_chart 表整型 chart_id,写链 addBiChartInfo 直存)。缺省 bi_chart(向后兼容既有声明)。
2563
- ref_kind: Literal["chart", "bi_chart"] | None = None
2564
2557
 
2565
2558
  @model_validator(mode="before")
2566
2559
  @classmethod
@@ -2580,18 +2573,12 @@ class PortalChartRefPatch(StrictModel):
2580
2573
  payload["chart_name"] = payload.pop("name")
2581
2574
  if "appKey" in payload and "app_key" not in payload:
2582
2575
  payload["app_key"] = payload.pop("appKey")
2583
- if "refKind" in payload and "ref_kind" not in payload:
2584
- payload["ref_kind"] = payload.pop("refKind")
2585
- if "kind" in payload and "ref_kind" not in payload:
2586
- payload["ref_kind"] = payload.pop("kind")
2587
2576
  return payload
2588
2577
 
2589
2578
  @model_validator(mode="after")
2590
2579
  def validate_target(self) -> "PortalChartRefPatch":
2591
2580
  if not (self.chart_id or self.chart_name):
2592
2581
  raise ValueError("chart_ref requires chart_id or chart_name")
2593
- if self.ref_kind == "chart" and not self.chart_id:
2594
- raise ValueError("chart_ref with ref_kind=chart requires chart_id (chart 表唯一键 chartKey)")
2595
2582
  if self.chart_name and not self.chart_id and not self.app_key:
2596
2583
  raise ValueError("chart_ref.app_key is required when resolving by chart_name")
2597
2584
  return self
@@ -2617,49 +2604,17 @@ class PortalViewRefPatch(StrictModel):
2617
2604
 
2618
2605
 
2619
2606
  class PortalSectionPatch(StrictModel):
2620
- # title 语义=组件显示标题(draft_dash_chart.component_title / grid_config.gridTitle 等),
2621
- # 生产存量存在空标题形态(显示标题开但标题空,读链回退视图名/图表名)——None=不设标题,
2622
- # 编译对 None 不落库(后端透传 NULL),round-trip 保真;手写声明缺省 title=None(不设)。
2623
- title: str | None = None
2607
+ title: str
2624
2608
  source_type: str = Field(validation_alias=AliasChoices("source_type", "sourceType"))
2625
2609
  role: str | None = Field(default=None, validation_alias=AliasChoices("role", "zone", "section_role", "sectionRole"))
2626
- # 显示标题开关(draft_dash_chart.being_show_title):提取侧读面必有值(True/False);
2627
- # 声明缺省 None 时编译回落产品默认 True(与既有创建语义兼容)。
2628
- show_title: bool | None = Field(
2629
- default=None,
2630
- validation_alias=AliasChoices("show_title", "showTitle", "being_show_title", "beingShowTitle"),
2631
- )
2632
2610
  position: PortalComponentPositionPatch | None = None
2633
- dash_style_config: dict[str, Any] | None = Field(
2634
- default=None,
2635
- validation_alias=AliasChoices("dash_style_config", "style_config", "dashStyleConfigBO", "dashStyleConfig"),
2636
- )
2611
+ dash_style_config: dict[str, Any] | None = Field(default=None, validation_alias=AliasChoices("dash_style_config", "dashStyleConfigBO"))
2637
2612
  config: dict[str, Any] = Field(default_factory=dict)
2638
2613
  chart_ref: PortalChartRefPatch | None = None
2639
2614
  chart: PortalInlineChartPatch | None = Field(default=None, validation_alias=AliasChoices("chart", "inline_chart", "inlineChart", "create_chart", "createChart"))
2640
2615
  view_ref: PortalViewRefPatch | None = None
2641
- view_display: dict[str, Any] | None = Field(
2642
- default=None,
2643
- validation_alias=AliasChoices("view_display", "viewDisplay"),
2644
- )
2645
2616
  text: str | None = None
2646
2617
  url: str | None = None
2647
- login_auth: bool | None = Field(
2648
- default=None,
2649
- validation_alias=AliasChoices("login_auth", "loginAuth", "being_login_auth", "beingLoginAuth"),
2650
- )
2651
- carousel: dict[str, Any] | None = Field(
2652
- default=None,
2653
- validation_alias=AliasChoices("carousel", "carousel_config", "carouselConfig"),
2654
- )
2655
- task: dict[str, Any] | None = Field(
2656
- default=None,
2657
- validation_alias=AliasChoices("task", "task_config", "taskConfig"),
2658
- )
2659
- favourite: dict[str, Any] | None = Field(
2660
- default=None,
2661
- validation_alias=AliasChoices("favourite", "favourite_config", "favouriteConfig"),
2662
- )
2663
2618
 
2664
2619
  @model_validator(mode="before")
2665
2620
  @classmethod
@@ -2704,7 +2659,7 @@ class PortalSectionPatch(StrictModel):
2704
2659
 
2705
2660
  @model_validator(mode="after")
2706
2661
  def validate_shape(self) -> "PortalSectionPatch":
2707
- supported = {"chart", "view", "grid", "filter", "text", "link", "carousel", "task", "favourite"}
2662
+ supported = {"chart", "view", "grid", "filter", "text", "link"}
2708
2663
  if self.source_type not in supported:
2709
2664
  raise ValueError(f"unsupported portal source_type '{self.source_type}'")
2710
2665
  if self.source_type == "chart" and self.chart_ref is None and self.chart is None:
@@ -2715,12 +2670,6 @@ class PortalSectionPatch(StrictModel):
2715
2670
  raise ValueError("text section requires text")
2716
2671
  if self.source_type == "link" and self.url is None:
2717
2672
  raise ValueError("link section requires url")
2718
- if self.source_type == "carousel" and self.carousel is None:
2719
- raise ValueError("carousel section requires carousel")
2720
- if self.source_type == "task" and self.task is None:
2721
- raise ValueError("task section requires task")
2722
- if self.source_type == "favourite" and self.favourite is None:
2723
- raise ValueError("favourite section requires favourite")
2724
2673
  return self
2725
2674
 
2726
2675
 
@@ -2736,20 +2685,8 @@ class PortalApplyRequest(StrictModel):
2736
2685
  icon: str | None = None
2737
2686
  color: str | None = None
2738
2687
  hide_copyright: bool | None = Field(default=None, validation_alias=AliasChoices("hide_copyright", "hideCopyright"))
2739
- global_config: dict[str, Any] | None = Field(
2740
- default=None,
2741
- validation_alias=AliasChoices("global_config", "globalConfig", "dash_global_config", "dashGlobalConfig"),
2742
- )
2743
- style_template_id: int | None = Field(
2744
- default=None,
2745
- validation_alias=AliasChoices("style_template_id", "styleTemplateId"),
2746
- )
2747
- overall_style: dict[str, Any] | None = Field(
2748
- default=None,
2749
- validation_alias=AliasChoices("overall_style", "overallStyle", "overallConfigBO"),
2750
- )
2688
+ dash_global_config: dict[str, Any] | None = Field(default=None, validation_alias=AliasChoices("dash_global_config", "dashGlobalConfig"))
2751
2689
  config: dict[str, Any] = Field(default_factory=dict)
2752
- schema_version: str | None = Field(default=None, validation_alias=AliasChoices("schema_version", "schemaVersion"))
2753
2690
 
2754
2691
  @model_validator(mode="before")
2755
2692
  @classmethod
@@ -2757,14 +2694,8 @@ class PortalApplyRequest(StrictModel):
2757
2694
  if not isinstance(value, dict):
2758
2695
  return value
2759
2696
  payload = dict(value)
2760
- payload.pop("schema_version", None)
2761
- payload.pop("schemaVersion", None)
2762
2697
  if "dash_name" not in payload and "dashName" not in payload and "name" in payload:
2763
2698
  payload["dash_name"] = payload.pop("name")
2764
- if "dash_global_config" in payload and "global_config" not in payload:
2765
- payload["global_config"] = payload.pop("dash_global_config")
2766
- elif "dashGlobalConfig" in payload and "global_config" not in payload:
2767
- payload["global_config"] = payload.pop("dashGlobalConfig")
2768
2699
  if "sections" not in payload and "pages" in payload:
2769
2700
  pages = payload.pop("pages")
2770
2701
  if not isinstance(pages, list):
@@ -2799,88 +2730,6 @@ class PortalApplyRequest(StrictModel):
2799
2730
  return self
2800
2731
 
2801
2732
 
2802
- def _public_portal_section_payload(section: PortalSectionPatch) -> dict[str, Any]:
2803
- """Dump one portal section with canonical naming for schema validation."""
2804
- payload: dict[str, Any] = {
2805
- "title": section.title,
2806
- "source_type": section.source_type,
2807
- }
2808
- if section.role is not None:
2809
- payload["role"] = section.role
2810
- if section.position is not None:
2811
- payload["position"] = {
2812
- "pc": {
2813
- "x": section.position.pc_x,
2814
- "y": section.position.pc_y,
2815
- "cols": section.position.pc_w,
2816
- "rows": section.position.pc_h,
2817
- },
2818
- }
2819
- if section.position.mobile_provided:
2820
- payload["position"]["mobile"] = {
2821
- "x": section.position.mobile_x,
2822
- "y": section.position.mobile_y,
2823
- "cols": section.position.mobile_w,
2824
- "rows": section.position.mobile_h,
2825
- }
2826
- if section.dash_style_config is not None:
2827
- payload["style_config"] = section.dash_style_config
2828
- if section.chart_ref is not None:
2829
- payload["chart_ref"] = section.chart_ref.model_dump(mode="json", exclude_none=True)
2830
- if section.chart is not None:
2831
- payload["chart"] = section.chart.model_dump(mode="json", exclude_none=True)
2832
- if section.view_ref is not None:
2833
- payload["view_ref"] = section.view_ref.model_dump(mode="json", exclude_none=True)
2834
- if section.view_display is not None:
2835
- payload["view_display"] = section.view_display
2836
- if section.text is not None:
2837
- payload["text"] = section.text
2838
- if section.url is not None:
2839
- payload["url"] = section.url
2840
- if section.login_auth is not None:
2841
- payload["login_auth"] = section.login_auth
2842
- if section.carousel is not None:
2843
- payload["carousel"] = section.carousel
2844
- if section.task is not None:
2845
- payload["task"] = section.task
2846
- if section.favourite is not None:
2847
- payload["favourite"] = section.favourite
2848
- if section.config:
2849
- payload["config"] = section.config
2850
- return payload
2851
-
2852
-
2853
- def public_portal_apply_payload(request: PortalApplyRequest) -> dict[str, Any]:
2854
- """Canonical-named portal declaration used for schema validation."""
2855
- payload: dict[str, Any] = {}
2856
- if request.dash_key:
2857
- payload["dash_key"] = request.dash_key
2858
- if request.dash_name is not None:
2859
- payload["name"] = request.dash_name
2860
- if request.package_tag_id is not None:
2861
- payload["package_tag_id"] = request.package_tag_id
2862
- payload["publish"] = request.publish
2863
- if request.sections is not None:
2864
- payload["sections"] = [_public_portal_section_payload(section) for section in request.sections]
2865
- if request.layout_preset is not None:
2866
- payload["layout_preset"] = request.layout_preset
2867
- if request.visibility is not None:
2868
- payload["visibility"] = request.visibility.model_dump(mode="json", exclude_none=True)
2869
- if request.icon is not None:
2870
- payload["icon"] = request.icon
2871
- if request.color is not None:
2872
- payload["color"] = request.color
2873
- if request.hide_copyright is not None:
2874
- payload["hide_copyright"] = request.hide_copyright
2875
- if request.global_config is not None:
2876
- payload["global_config"] = request.global_config
2877
- if request.style_template_id is not None:
2878
- payload["style_template_id"] = request.style_template_id
2879
- if request.overall_style is not None:
2880
- payload["overall_style"] = request.overall_style
2881
- return payload
2882
-
2883
-
2884
2733
  FieldPatch.model_rebuild()
2885
2734
  FieldMutation.model_rebuild()
2886
2735
  FieldUpdatePatch.model_rebuild()
@@ -10,7 +10,6 @@
10
10
  "fieldTypes": [
11
11
  "text",
12
12
  "long_text",
13
- "rich_text",
14
13
  "number",
15
14
  "amount",
16
15
  "link",
@@ -29,20 +28,7 @@
29
28
  "code_block",
30
29
  "data_relation",
31
30
  "relation",
32
- "subtable",
33
- "date_duration",
34
- "image_select",
35
- "location",
36
- "ocr",
37
- "embed_field",
38
- "ai_content_generation",
39
- "ai_content_extraction",
40
- "ai_content_classification",
41
- "ai_machine_translation",
42
- "ai_image_recognition",
43
- "ai_image_generation",
44
- "ai_document_parsing",
45
- "ai_text_summary"
31
+ "subtable"
46
32
  ],
47
33
  "normalizerVersion": "v1alpha1",
48
34
  "schemaKinds": [
@@ -239,7 +239,7 @@
239
239
  ]
240
240
  },
241
241
  "fileSize": {
242
- "minimum": 0,
242
+ "minimum": 1,
243
243
  "type": [
244
244
  "integer",
245
245
  "null"
@@ -259,7 +259,7 @@
259
259
  ]
260
260
  },
261
261
  "maxFileLimit": {
262
- "minimum": 0,
262
+ "minimum": 1,
263
263
  "type": [
264
264
  "integer",
265
265
  "null"
@@ -518,7 +518,7 @@
518
518
  },
519
519
  "DataRelationCondition": {
520
520
  "additionalProperties": false,
521
- "description": "一条数据关联过滤条件;sourceField 必须属于数据来源,operator 必须适用于该字段类型。固定值请使用 literal operand,不要直接声明后端 matchRules。sourceField 省略为存量读回形态(历史脏公式的源字段缺失,如 #queId_0$,写回时以 queId=0 透传),新建条件应提供 sourceField。",
521
+ "description": "一条数据关联过滤条件;sourceField 必须属于数据来源,operator 必须适用于该字段类型。固定值请使用 literal operand,不要直接声明后端 matchRules。",
522
522
  "properties": {
523
523
  "operand": {
524
524
  "$ref": "#/$defs/DataRelationOperand",
@@ -554,10 +554,11 @@
554
554
  },
555
555
  "sourceField": {
556
556
  "$ref": "#/$defs/FieldSelector",
557
- "description": "被过滤的数据源字段;存量读回形态可能缺失(后端反解析出的条件源字段 queId=0 且无名称)。"
557
+ "description": "被过滤的数据源字段。"
558
558
  }
559
559
  },
560
560
  "required": [
561
+ "sourceField",
561
562
  "operator",
562
563
  "operand"
563
564
  ],
@@ -565,7 +566,7 @@
565
566
  },
566
567
  "DataRelationConfig": {
567
568
  "additionalProperties": false,
568
- "description": "数据关联字段配置;从应用、Q-Linker 或代码块输出中读取数据。source 省略表示该字段当前无关联来源配置(存量表单读回形态:后端 GET 对 displayed 目标缺失的 relation 行不回传,FormSvcImpl#getQuestionRelationsBeans continue 分支;新建数据关联字段应提供 source)。",
569
+ "description": "数据关联字段配置;从应用、Q-Linker 或代码块输出中读取数据。",
569
570
  "properties": {
570
571
  "aggregation": {
571
572
  "description": "可选聚合方式;null 表示不聚合。",
@@ -600,10 +601,12 @@
600
601
  },
601
602
  "source": {
602
603
  "$ref": "#/$defs/DataRelationSource",
603
- "description": "数据来源;按 kind 选择一种来源结构。存量读回形态可能无 source(后端读面不回传关联配置),此时写回不重建该字段的关联。"
604
+ "description": "数据来源;按 kind 选择一种来源结构。"
604
605
  }
605
606
  },
606
- "required": [],
607
+ "required": [
608
+ "source"
609
+ ],
607
610
  "type": "object"
608
611
  },
609
612
  "DataRelationCustomButton": {
@@ -910,12 +913,6 @@
910
913
  "null"
911
914
  ]
912
915
  },
913
- "auditValueDescription": {
914
- "type": [
915
- "string",
916
- "null"
917
- ]
918
- },
919
916
  "beingCanDecrypted": {
920
917
  "type": [
921
918
  "boolean",
@@ -946,12 +943,6 @@
946
943
  "null"
947
944
  ]
948
945
  },
949
- "dataId": {
950
- "type": [
951
- "integer",
952
- "null"
953
- ]
954
- },
955
946
  "dateType": {
956
947
  "type": [
957
948
  "integer",
@@ -970,15 +961,6 @@
970
961
  "null"
971
962
  ]
972
963
  },
973
- "previousTableRowOrdinalList": {
974
- "items": {
975
- "type": "integer"
976
- },
977
- "type": [
978
- "array",
979
- "null"
980
- ]
981
- },
982
964
  "queId": {
983
965
  "type": [
984
966
  "integer",
@@ -997,12 +979,6 @@
997
979
  "null"
998
980
  ]
999
981
  },
1000
- "questionOrdinal": {
1001
- "type": [
1002
- "integer",
1003
- "null"
1004
- ]
1005
- },
1006
982
  "referValues": {
1007
983
  "items": {
1008
984
  "$ref": "#/$defs/ReferenceDefaultValue"
@@ -1302,7 +1278,7 @@
1302
1278
  "description": "普通字段的默认值;后端 queDefaultValue 为字符串,因此数字等字面量也必须以字符串传入。defaultType 为 1 时表示静态文本,为 3 时表示公式文本,为 2 时不携带字面量默认值。表格、地址、附件、引用等结构化默认值必须放在具体字段 config.defaultValues。显式 null 表示清除默认值。"
1303
1279
  },
1304
1280
  "name": {
1305
- "description": "字段展示名称;新增字段必填,已有字段可在携带 queId 时省略;同父级允许同名(后端以 queId 为字段身份),配置引用建议携带 queId。",
1281
+ "description": "字段展示名称;新增字段必填,已有字段可在携带 queId 时省略;同一父级内唯一。",
1306
1282
  "minLength": 1,
1307
1283
  "type": "string"
1308
1284
  },
@@ -1323,9 +1299,13 @@
1323
1299
  "type": "string"
1324
1300
  },
1325
1301
  "width": {
1326
- "description": "字段在所在行的宽度百分比(1-100 整数);后端不校验总和与取值,存量数据存在 33/34 等三等分布值。",
1327
- "maximum": 100,
1328
- "minimum": 1,
1302
+ "description": "字段在所在行的宽度百分比;只能选择 25、50、75 或 100。",
1303
+ "enum": [
1304
+ 25,
1305
+ 50,
1306
+ 75,
1307
+ 100
1308
+ ],
1329
1309
  "type": "integer"
1330
1310
  }
1331
1311
  },
@@ -1336,11 +1316,11 @@
1336
1316
  "description": "段落内部字段行。",
1337
1317
  "properties": {
1338
1318
  "fields": {
1339
- "description": "本行的 1 到 12 个顶层字段(后端无每行字段数上限,按 queWidth 渲染;上限仅约束声明输入)。",
1319
+ "description": "本行的 1 到 4 个顶层字段。",
1340
1320
  "items": {
1341
1321
  "$ref": "#/$defs/TopField"
1342
1322
  },
1343
- "maxItems": 12,
1323
+ "maxItems": 4,
1344
1324
  "minItems": 1,
1345
1325
  "type": "array"
1346
1326
  }
@@ -1364,10 +1344,10 @@
1364
1344
  ]
1365
1345
  }
1366
1346
  ],
1367
- "description": "字段选择器;用于定位应用的数据标题、数据封面、自定义编号取值来源或其他配置引用的字段。至少提供 queId 或 name,两者同时提供时必须指向同一字段。后端允许同父级同名字段,queId 是稳定身份;name 仅在唯一时可解析,命中多个同名时报 AMBIGUOUS_FIELD_SELECTOR,此时必须改用 queId。",
1347
+ "description": "字段选择器;用于定位应用的数据标题、数据封面、自定义编号取值来源或其他配置引用的字段。至少提供 queId 或 name,两者同时提供时必须指向同一字段。",
1368
1348
  "properties": {
1369
1349
  "name": {
1370
- "description": "字段名称;仅在当前作用域内唯一时可用于解析,同名命中多个字段时报 AMBIGUOUS_FIELD_SELECTOR,应改用 queId。",
1350
+ "description": "字段名称;仅在当前作用域内唯一时可用于解析。",
1371
1351
  "minLength": 1,
1372
1352
  "type": "string"
1373
1353
  },
@@ -1653,8 +1633,8 @@
1653
1633
  ]
1654
1634
  },
1655
1635
  "numberFormat": {
1656
- "description": "数字展示格式 ID(1 默认/2 千分位/3 百分比;0 为历史存量值——后端写链无值域校验,原样落库回读)。",
1657
- "minimum": 0,
1636
+ "description": "数字展示格式 ID。",
1637
+ "minimum": 1,
1658
1638
  "type": [
1659
1639
  "integer",
1660
1640
  "null"
@@ -1945,8 +1925,8 @@
1945
1925
  ]
1946
1926
  },
1947
1927
  "url": {
1948
- "description": "请求 URL;动态嵌入字段值时使用 {{key}},并在 inputs 中提供同名 source=json_path 映射。自定义模式(configMode=1)后端要求非空;插件模板/连接中心/轻翼智能体模式的 URL 由模板侧提供,存量声明可为空字符串(写回按读面形态透传)。",
1949
- "minLength": 0,
1928
+ "description": "请求 URL;动态嵌入字段值时使用 {{key}},并在 inputs 中提供同名 source=json_path 映射。",
1929
+ "minLength": 1,
1950
1930
  "type": "string"
1951
1931
  },
1952
1932
  "urlEncodedValue": {
@@ -1995,7 +1975,7 @@
1995
1975
  },
1996
1976
  "RelationConfig": {
1997
1977
  "additionalProperties": false,
1998
- "description": "引用字段配置;引用其他应用中的数据。展示字段与权限以 displayFields 为准(后端 referQuestions 全量有序回写,queAuth 1=可编辑/2=隐藏/3=仅可见);displayField/visibleFields 为已废弃旧形态,apply 兼容接收一个版本窗口(displayField 同时视为双向绑定目标)。",
1978
+ "description": "引用字段配置;引用其他应用中的数据。",
1999
1979
  "properties": {
2000
1980
  "beingDefaultFormulaAutoFillEnabled": {
2001
1981
  "description": "是否启用引用字段的默认值公式自动填充。",
@@ -2033,32 +2013,7 @@
2033
2013
  },
2034
2014
  "displayField": {
2035
2015
  "$ref": "#/$defs/FieldSelector",
2036
- "description": "已废弃:主展示字段;apply 兼容翻译为 twoWayBoundField + displayFields 首项,后续版本移除。"
2037
- },
2038
- "displayFields": {
2039
- "description": "有序展示字段全量列表(含隐藏字段),按 ordinal 保序回写为后端 referQuestions。可为空列表:空 = 双向绑定未配展示字段的合法存量形态(后端写链路对空 referQuestions 跳过插入、读面容忍空),round-trip 空↔空稳定;与已废弃 displayField/visibleFields 不可混用,条目 queId 不可重复。",
2040
- "items": {
2041
- "additionalProperties": false,
2042
- "properties": {
2043
- "auth": {
2044
- "default": "visible",
2045
- "description": "展示字段权限;editable=可编辑(1), hidden=隐藏(2), visible=仅可见(3);缺失按 visible。",
2046
- "enum": [
2047
- "editable",
2048
- "hidden",
2049
- "visible"
2050
- ]
2051
- },
2052
- "field": {
2053
- "$ref": "#/$defs/FieldSelector"
2054
- }
2055
- },
2056
- "required": [
2057
- "field"
2058
- ],
2059
- "type": "object"
2060
- },
2061
- "type": "array"
2016
+ "description": "引用值的主展示字段。"
2062
2017
  },
2063
2018
  "relationMode": {
2064
2019
  "default": "single",
@@ -2073,19 +2028,8 @@
2073
2028
  "minLength": 1,
2074
2029
  "type": "string"
2075
2030
  },
2076
- "twoWayBoundField": {
2077
- "description": "双向引用绑定的目标字段(后端 referQueId);null/省略 = 单向引用。get 读面在 referQueId 非空时必产出。",
2078
- "oneOf": [
2079
- {
2080
- "type": "null"
2081
- },
2082
- {
2083
- "$ref": "#/$defs/FieldSelector"
2084
- }
2085
- ]
2086
- },
2087
2031
  "visibleFields": {
2088
- "description": "已废弃:额外展示字段;apply 兼容翻译为 displayFields 后续项,后续版本移除。",
2032
+ "description": "引用选择界面额外展示的字段。",
2089
2033
  "items": {
2090
2034
  "$ref": "#/$defs/FieldSelector"
2091
2035
  },
@@ -2094,7 +2038,8 @@
2094
2038
  }
2095
2039
  },
2096
2040
  "required": [
2097
- "targetAppKey"
2041
+ "targetAppKey",
2042
+ "displayField"
2098
2043
  ],
2099
2044
  "type": "object"
2100
2045
  },
@@ -2120,11 +2065,11 @@
2120
2065
  "description": "根级普通字段行;字段顺序即展示顺序。",
2121
2066
  "properties": {
2122
2067
  "fields": {
2123
- "description": "本行的 1 到 12 个顶层字段(后端无每行字段数上限,按 queWidth 渲染;上限仅约束声明输入)。",
2068
+ "description": "本行的 1 到 4 个顶层字段。",
2124
2069
  "items": {
2125
2070
  "$ref": "#/$defs/TopField"
2126
2071
  },
2127
- "maxItems": 12,
2072
+ "maxItems": 4,
2128
2073
  "minItems": 1,
2129
2074
  "type": "array"
2130
2075
  },
@@ -2155,10 +2100,11 @@
2155
2100
  "description": "段落判别值。"
2156
2101
  },
2157
2102
  "rows": {
2158
- "description": "段落内的有序字段行;可为空数组(空 = 存量空段落形态,后端容忍,round-trip 空↔空稳定)。",
2103
+ "description": "段落内的非空有序字段行。",
2159
2104
  "items": {
2160
2105
  "$ref": "#/$defs/FieldRow"
2161
2106
  },
2107
+ "minItems": 1,
2162
2108
  "type": "array"
2163
2109
  },
2164
2110
  "sectionId": {
@@ -2439,10 +2385,7 @@
2439
2385
  "$ref": "#/$defs/NumberConfig"
2440
2386
  },
2441
2387
  "questionType": {
2442
- "enum": [
2443
- "number",
2444
- "amount"
2445
- ]
2388
+ "const": "number"
2446
2389
  }
2447
2390
  },
2448
2391
  "required": [
@@ -2455,10 +2398,7 @@
2455
2398
  "$ref": "#/$defs/EmptyConfig"
2456
2399
  },
2457
2400
  "questionType": {
2458
- "enum": [
2459
- "date",
2460
- "datetime"
2461
- ]
2401
+ "const": "date"
2462
2402
  }
2463
2403
  },
2464
2404
  "required": [
@@ -2762,21 +2702,7 @@
2762
2702
  "questionType": {
2763
2703
  "enum": [
2764
2704
  "date",
2765
- "datetime",
2766
- "rich_text",
2767
- "date_duration",
2768
- "image_select",
2769
- "location",
2770
- "ocr",
2771
- "embed_field",
2772
- "ai_content_generation",
2773
- "ai_content_extraction",
2774
- "ai_content_classification",
2775
- "ai_machine_translation",
2776
- "ai_image_recognition",
2777
- "ai_image_generation",
2778
- "ai_document_parsing",
2779
- "ai_text_summary"
2705
+ "datetime"
2780
2706
  ]
2781
2707
  }
2782
2708
  },