dsh-crwu-workbench 0.0.10

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 (479) hide show
  1. package/CHANGELOG.md +1516 -0
  2. package/LICENSE +26 -0
  3. package/README.en.md +204 -0
  4. package/README.md +521 -0
  5. package/SECURITY.md +39 -0
  6. package/bin/darwin-arm64/crwu +0 -0
  7. package/bin/darwin-arm64/dws +0 -0
  8. package/bin/darwin-arm64/ossutil +0 -0
  9. package/bin/manifest.json +82 -0
  10. package/bin/win32-x64/crwu.exe +0 -0
  11. package/bin/win32-x64/dws.exe +4 -0
  12. package/bin/win32-x64/ossutil.exe +0 -0
  13. package/common/skills/.synced.json +8 -0
  14. package/common/skills/crwu-dws/SKILL.md +208 -0
  15. package/common/skills/crwu-dws/references/00-/347/233/256/345/275/225/345/277/253/347/205/247schema.md +113 -0
  16. package/common/skills/crwu-dws/references/01-/345/256/241/346/240/270/344/270/213/350/275/275/344/270/216manifest/350/247/204/350/214/203.md +115 -0
  17. package/common/skills/crwu-dws/references/02-/347/274/223/345/255/230/344/270/216/345/205/234/345/272/225/346/237/245/346/211/276/350/247/204/350/214/203.md +119 -0
  18. package/common/skills/crwu-dws/scripts/test_dws_source_contract.py +493 -0
  19. package/common/skills/crwu-h3yun-login/SKILL.md +130 -0
  20. package/common/skills/crwu-h3yun-query/SKILL.md +192 -0
  21. package/config/crwu-workbench.yml +26 -0
  22. package/cordis.patch.yml +46 -0
  23. package/lib/client.js +10346 -0
  24. package/lib/index.js +11584 -0
  25. package/package.json +119 -0
  26. package/scripts/prepare.mjs +59 -0
  27. package/skills/README.md +26 -0
  28. package/skills/crwu/crwu-audit/SKILL.md +152 -0
  29. package/skills/crwu/crwu-audit/references/00-input-and-route-profile.md +232 -0
  30. package/skills/crwu/crwu-audit/references/01-report-id-resolution.md +13 -0
  31. package/skills/crwu/crwu-audit/references/02-scope-classification.md +25 -0
  32. package/skills/crwu/crwu-audit/references/03-asset-classification.md +27 -0
  33. package/skills/crwu/crwu-audit/references/04-business-classification.md +63 -0
  34. package/skills/crwu/crwu-audit/references/05-method-classification.md +66 -0
  35. package/skills/crwu/crwu-audit/references/06-overlay-classification.md +42 -0
  36. package/skills/crwu/crwu-audit/references/07-skill-registry.md +57 -0
  37. package/skills/crwu/crwu-audit/references/08-union-dispatch-rules.md +142 -0
  38. package/skills/crwu/crwu-audit/references/09-review-risk-classification.md +85 -0
  39. package/skills/crwu/crwu-audit/references/10-capability-gap-proposal.md +68 -0
  40. package/skills/crwu/crwu-audit/references/11-html-delivery-spec.md +881 -0
  41. package/skills/crwu/crwu-audit/references/12-leaf-common-contract.md +202 -0
  42. package/skills/crwu/crwu-audit/references/13-dingtalk-result-publish.md +88 -0
  43. package/skills/crwu/crwu-audit/references/14-orchestration-workflow.md +52 -0
  44. package/skills/crwu/crwu-audit/references/99-maintenance.md +62 -0
  45. package/skills/crwu/crwu-audit/scripts/README.md +157 -0
  46. package/skills/crwu/crwu-audit/scripts/audit_delivery.py +2736 -0
  47. package/skills/crwu/crwu-audit/scripts/audit_result.schema.json +1659 -0
  48. package/skills/crwu/crwu-audit/scripts/examples/audit-result.sample.json +739 -0
  49. package/skills/crwu/crwu-audit/scripts/fetch_review_records.py +85 -0
  50. package/skills/crwu/crwu-audit/scripts/media_extract.py +513 -0
  51. package/skills/crwu/crwu-audit/scripts/prepare_materials.py +1252 -0
  52. package/skills/crwu/crwu-audit/scripts/test_audit_delivery.py +1678 -0
  53. package/skills/crwu/crwu-audit/scripts/test_audit_multiaxis_router.py +1339 -0
  54. package/skills/crwu/crwu-audit/scripts/test_fetch_review_records.py +77 -0
  55. package/skills/crwu/crwu-audit/scripts/test_media_extract.py +332 -0
  56. package/skills/crwu/crwu-audit/scripts/test_prepare_materials.py +1081 -0
  57. package/skills/crwu/crwu-audit/template/audit-report.html +435 -0
  58. package/skills/crwu/crwu-audit-asset-asset-group-goodwill/SKILL.md +38 -0
  59. package/skills/crwu/crwu-audit-asset-asset-group-goodwill/references/00-applicability.md +28 -0
  60. package/skills/crwu/crwu-audit-asset-asset-group-goodwill/references/01-kb-assembly.md +31 -0
  61. package/skills/crwu/crwu-audit-asset-asset-group-goodwill/references/02-review-focus.md +21 -0
  62. package/skills/crwu/crwu-audit-asset-asset-group-goodwill/references/03-common-contract.md +202 -0
  63. package/skills/crwu/crwu-audit-asset-debt/SKILL.md +38 -0
  64. package/skills/crwu/crwu-audit-asset-debt/references/00-applicability.md +40 -0
  65. package/skills/crwu/crwu-audit-asset-debt/references/01-kb-assembly.md +41 -0
  66. package/skills/crwu/crwu-audit-asset-debt/references/02-review-focus.md +54 -0
  67. package/skills/crwu/crwu-audit-asset-debt/references/03-common-contract.md +202 -0
  68. package/skills/crwu/crwu-audit-asset-enterprise-value/SKILL.md +38 -0
  69. package/skills/crwu/crwu-audit-asset-enterprise-value/references/00-applicability.md +31 -0
  70. package/skills/crwu/crwu-audit-asset-enterprise-value/references/01-kb-assembly.md +35 -0
  71. package/skills/crwu/crwu-audit-asset-enterprise-value/references/02-review-focus.md +33 -0
  72. package/skills/crwu/crwu-audit-asset-enterprise-value/references/03-common-contract.md +202 -0
  73. package/skills/crwu/crwu-audit-asset-equipment/SKILL.md +38 -0
  74. package/skills/crwu/crwu-audit-asset-equipment/references/00-applicability.md +40 -0
  75. package/skills/crwu/crwu-audit-asset-equipment/references/01-kb-assembly.md +39 -0
  76. package/skills/crwu/crwu-audit-asset-equipment/references/02-review-focus.md +52 -0
  77. package/skills/crwu/crwu-audit-asset-equipment/references/03-common-contract.md +202 -0
  78. package/skills/crwu/crwu-audit-asset-intangible/SKILL.md +38 -0
  79. package/skills/crwu/crwu-audit-asset-intangible/references/00-applicability.md +36 -0
  80. package/skills/crwu/crwu-audit-asset-intangible/references/01-kb-assembly.md +40 -0
  81. package/skills/crwu/crwu-audit-asset-intangible/references/02-review-focus.md +68 -0
  82. package/skills/crwu/crwu-audit-asset-intangible/references/03-common-contract.md +202 -0
  83. package/skills/crwu/crwu-audit-asset-inventory/SKILL.md +38 -0
  84. package/skills/crwu/crwu-audit-asset-inventory/references/00-applicability.md +28 -0
  85. package/skills/crwu/crwu-audit-asset-inventory/references/01-kb-assembly.md +31 -0
  86. package/skills/crwu/crwu-audit-asset-inventory/references/02-review-focus.md +21 -0
  87. package/skills/crwu/crwu-audit-asset-inventory/references/03-common-contract.md +202 -0
  88. package/skills/crwu/crwu-audit-asset-mining-right/SKILL.md +38 -0
  89. package/skills/crwu/crwu-audit-asset-mining-right/references/00-applicability.md +31 -0
  90. package/skills/crwu/crwu-audit-asset-mining-right/references/01-kb-assembly.md +35 -0
  91. package/skills/crwu/crwu-audit-asset-mining-right/references/02-review-focus.md +33 -0
  92. package/skills/crwu/crwu-audit-asset-mining-right/references/03-common-contract.md +202 -0
  93. package/skills/crwu/crwu-audit-asset-other/SKILL.md +38 -0
  94. package/skills/crwu/crwu-audit-asset-other/references/00-applicability.md +28 -0
  95. package/skills/crwu/crwu-audit-asset-other/references/01-kb-assembly.md +31 -0
  96. package/skills/crwu/crwu-audit-asset-other/references/02-review-focus.md +21 -0
  97. package/skills/crwu/crwu-audit-asset-other/references/03-common-contract.md +202 -0
  98. package/skills/crwu/crwu-audit-asset-portfolio/SKILL.md +38 -0
  99. package/skills/crwu/crwu-audit-asset-portfolio/references/00-applicability.md +28 -0
  100. package/skills/crwu/crwu-audit-asset-portfolio/references/01-kb-assembly.md +31 -0
  101. package/skills/crwu/crwu-audit-asset-portfolio/references/02-review-focus.md +21 -0
  102. package/skills/crwu/crwu-audit-asset-portfolio/references/03-common-contract.md +202 -0
  103. package/skills/crwu/crwu-audit-asset-realestate/SKILL.md +38 -0
  104. package/skills/crwu/crwu-audit-asset-realestate/references/00-applicability.md +43 -0
  105. package/skills/crwu/crwu-audit-asset-realestate/references/01-kb-assembly.md +75 -0
  106. package/skills/crwu/crwu-audit-asset-realestate/references/02-review-focus.md +93 -0
  107. package/skills/crwu/crwu-audit-asset-realestate/references/03-common-contract.md +202 -0
  108. package/skills/crwu/crwu-audit-asset-scrap-materials/SKILL.md +38 -0
  109. package/skills/crwu/crwu-audit-asset-scrap-materials/references/00-applicability.md +28 -0
  110. package/skills/crwu/crwu-audit-asset-scrap-materials/references/01-kb-assembly.md +31 -0
  111. package/skills/crwu/crwu-audit-asset-scrap-materials/references/02-review-focus.md +21 -0
  112. package/skills/crwu/crwu-audit-asset-scrap-materials/references/03-common-contract.md +202 -0
  113. package/skills/crwu/crwu-audit-asset-transport-equipment/SKILL.md +38 -0
  114. package/skills/crwu/crwu-audit-asset-transport-equipment/references/00-applicability.md +31 -0
  115. package/skills/crwu/crwu-audit-asset-transport-equipment/references/01-kb-assembly.md +35 -0
  116. package/skills/crwu/crwu-audit-asset-transport-equipment/references/02-review-focus.md +33 -0
  117. package/skills/crwu/crwu-audit-asset-transport-equipment/references/03-common-contract.md +202 -0
  118. package/skills/crwu/crwu-audit-biz-asset-operation/SKILL.md +38 -0
  119. package/skills/crwu/crwu-audit-biz-asset-operation/references/00-applicability.md +30 -0
  120. package/skills/crwu/crwu-audit-biz-asset-operation/references/01-kb-assembly.md +32 -0
  121. package/skills/crwu/crwu-audit-biz-asset-operation/references/02-review-focus.md +42 -0
  122. package/skills/crwu/crwu-audit-biz-asset-operation/references/03-common-contract.md +202 -0
  123. package/skills/crwu/crwu-audit-biz-consulting-review/SKILL.md +38 -0
  124. package/skills/crwu/crwu-audit-biz-consulting-review/references/00-applicability.md +30 -0
  125. package/skills/crwu/crwu-audit-biz-consulting-review/references/01-kb-assembly.md +32 -0
  126. package/skills/crwu/crwu-audit-biz-consulting-review/references/02-review-focus.md +40 -0
  127. package/skills/crwu/crwu-audit-biz-consulting-review/references/03-common-contract.md +202 -0
  128. package/skills/crwu/crwu-audit-biz-financial-reporting/SKILL.md +38 -0
  129. package/skills/crwu/crwu-audit-biz-financial-reporting/references/00-applicability.md +41 -0
  130. package/skills/crwu/crwu-audit-biz-financial-reporting/references/01-kb-assembly.md +40 -0
  131. package/skills/crwu/crwu-audit-biz-financial-reporting/references/02-review-focus.md +64 -0
  132. package/skills/crwu/crwu-audit-biz-financial-reporting/references/03-common-contract.md +202 -0
  133. package/skills/crwu/crwu-audit-biz-financing-debt/SKILL.md +38 -0
  134. package/skills/crwu/crwu-audit-biz-financing-debt/references/00-applicability.md +31 -0
  135. package/skills/crwu/crwu-audit-biz-financing-debt/references/01-kb-assembly.md +34 -0
  136. package/skills/crwu/crwu-audit-biz-financing-debt/references/02-review-focus.md +47 -0
  137. package/skills/crwu/crwu-audit-biz-financing-debt/references/03-common-contract.md +202 -0
  138. package/skills/crwu/crwu-audit-biz-investment-capital/SKILL.md +38 -0
  139. package/skills/crwu/crwu-audit-biz-investment-capital/references/00-applicability.md +31 -0
  140. package/skills/crwu/crwu-audit-biz-investment-capital/references/01-kb-assembly.md +34 -0
  141. package/skills/crwu/crwu-audit-biz-investment-capital/references/02-review-focus.md +47 -0
  142. package/skills/crwu/crwu-audit-biz-investment-capital/references/03-common-contract.md +202 -0
  143. package/skills/crwu/crwu-audit-biz-judicial-liquidation-compensation/SKILL.md +38 -0
  144. package/skills/crwu/crwu-audit-biz-judicial-liquidation-compensation/references/00-applicability.md +30 -0
  145. package/skills/crwu/crwu-audit-biz-judicial-liquidation-compensation/references/01-kb-assembly.md +32 -0
  146. package/skills/crwu/crwu-audit-biz-judicial-liquidation-compensation/references/02-review-focus.md +40 -0
  147. package/skills/crwu/crwu-audit-biz-judicial-liquidation-compensation/references/03-common-contract.md +202 -0
  148. package/skills/crwu/crwu-audit-biz-tax-history/SKILL.md +38 -0
  149. package/skills/crwu/crwu-audit-biz-tax-history/references/00-applicability.md +29 -0
  150. package/skills/crwu/crwu-audit-biz-tax-history/references/01-kb-assembly.md +30 -0
  151. package/skills/crwu/crwu-audit-biz-tax-history/references/02-review-focus.md +33 -0
  152. package/skills/crwu/crwu-audit-biz-tax-history/references/03-common-contract.md +202 -0
  153. package/skills/crwu/crwu-audit-biz-transaction-disposal/SKILL.md +38 -0
  154. package/skills/crwu/crwu-audit-biz-transaction-disposal/references/00-applicability.md +31 -0
  155. package/skills/crwu/crwu-audit-biz-transaction-disposal/references/01-kb-assembly.md +34 -0
  156. package/skills/crwu/crwu-audit-biz-transaction-disposal/references/02-review-focus.md +47 -0
  157. package/skills/crwu/crwu-audit-biz-transaction-disposal/references/03-common-contract.md +202 -0
  158. package/skills/crwu/crwu-audit-datacheck/SKILL.md +59 -0
  159. package/skills/crwu/crwu-audit-datacheck/references/00-KB/350/243/205/351/205/215/350/241/250.md +25 -0
  160. package/skills/crwu/crwu-audit-datacheck/references/01-runtime-and-check-catalog.md +139 -0
  161. package/skills/crwu/crwu-audit-datacheck/scripts/recalc_check.py +521 -0
  162. package/skills/crwu/crwu-audit-datacheck/scripts/test_recalc_check.py +419 -0
  163. package/skills/crwu/crwu-audit-datacheck/scripts/test_skill_self_containment.py +44 -0
  164. package/skills/crwu/crwu-audit-external-data/SKILL.md +73 -0
  165. package/skills/crwu/crwu-audit-external-data/references/00-KB/350/243/205/351/205/215/350/241/250.md +38 -0
  166. package/skills/crwu/crwu-audit-external-data/references/01-connector-access.md +116 -0
  167. package/skills/crwu/crwu-audit-external-data/references/02-verification-workflow.md +78 -0
  168. package/skills/crwu/crwu-audit-external-data/scripts/connector_probe.py +374 -0
  169. package/skills/crwu/crwu-audit-external-data/scripts/test_connector_probe.py +264 -0
  170. package/skills/crwu/crwu-audit-output-filter/SKILL.md +34 -0
  171. package/skills/crwu/crwu-audit-output-filter/references/00-applicability.md +7 -0
  172. package/skills/crwu/crwu-audit-output-filter/references/01-kb-assembly.md +11 -0
  173. package/skills/crwu/crwu-audit-output-filter/references/02-review-focus.md +25 -0
  174. package/skills/crwu/crwu-audit-public-general-standards/SKILL.md +46 -0
  175. package/skills/crwu/crwu-audit-public-general-standards/references/00-applicability.md +41 -0
  176. package/skills/crwu/crwu-audit-public-general-standards/references/01-kb-assembly.md +66 -0
  177. package/skills/crwu/crwu-audit-public-general-standards/references/02-review-focus.md +111 -0
  178. package/skills/crwu/crwu-audit-public-general-standards/references/03-execution-contract.md +89 -0
  179. package/skills/crwu/crwu-dev-audit-optimize/SKILL.md +98 -0
  180. package/skills/crwu/crwu-dev-audit-optimize/references/00-/344/274/230/345/214/226/350/247/204/350/214/203/344/270/216/346/226/207/344/273/266/350/220/275/347/202/271.md +132 -0
  181. package/skills/crwu/crwu-dev-audit-optimize/references/01-/345/217/215/351/246/210/345/256/232/344/275/215/344/270/216/347/224/273/345/203/217/346/265/201/347/250/213.md +108 -0
  182. package/skills/crwu/crwu-dev-audit-optimize/references/02-/346/226/271/346/241/210/346/250/241/346/235/277/344/270/216/347/241/256/350/256/244/351/227/250/347/246/201.md +92 -0
  183. package/skills/crwu/crwu-dev-audit-optimize/references/03-AI/344/272/272/345/267/245/345/267/256/350/267/235/345/210/206/346/236/220/346/265/201/347/250/213.md +95 -0
  184. package/skills/crwu/crwu-dev-audit-optimize/scripts/examples/gap-analysis.sample.json +116 -0
  185. package/skills/crwu/crwu-dev-audit-optimize/scripts/gap_analysis.schema.json +33 -0
  186. package/skills/crwu/crwu-dev-audit-optimize/scripts/gap_analysis_delivery.py +475 -0
  187. package/skills/crwu/crwu-dev-audit-optimize/scripts/test_gap_analysis_delivery.py +855 -0
  188. package/skills/crwu/crwu-dev-audit-optimize/template/NOTICE.echarts.txt +7 -0
  189. package/skills/crwu/crwu-dev-audit-optimize/template/echarts.min.js +45 -0
  190. package/skills/crwu/crwu-dev-audit-optimize/template/gap-analysis-report.html +71 -0
  191. package/skills/crwu/crwu-dev-audit-skill-maintainer/SKILL.md +74 -0
  192. package/skills/crwu/crwu-dev-audit-skill-maintainer/references/00-responsibility-and-modes.md +62 -0
  193. package/skills/crwu/crwu-dev-audit-skill-maintainer/references/01-kb-source-discovery.md +89 -0
  194. package/skills/crwu/crwu-dev-audit-skill-maintainer/references/02-child-skill-contract.md +99 -0
  195. package/skills/crwu/crwu-dev-audit-skill-maintainer/references/03-review-item-execution-contract.md +51 -0
  196. package/skills/crwu/crwu-dev-audit-skill-maintainer/references/04-registry-and-mapping-update.md +73 -0
  197. package/skills/crwu/crwu-dev-audit-skill-maintainer/references/05-validation-and-delivery.md +127 -0
  198. package/skills/crwu/crwu-dev-audit-skill-maintainer/references/06-live-routing-reconciliation.md +136 -0
  199. package/skills/crwu/crwu-dev-audit-skill-maintainer/references/07-kb-skill-map.md +411 -0
  200. package/skills/crwu/crwu-dev-audit-skill-maintainer/scripts/README.md +200 -0
  201. package/skills/crwu/crwu-dev-audit-skill-maintainer/scripts/check_audit_skill_mappings.py +2477 -0
  202. package/skills/crwu/crwu-dev-audit-skill-maintainer/scripts/kb_tool.py +577 -0
  203. package/skills/crwu/crwu-dev-audit-skill-maintainer/scripts/test_audit_skill_maintainer.py +5097 -0
  204. package/skills/dws/LICENSE +178 -0
  205. package/skills/dws/NOTICE +17 -0
  206. package/skills/dws/dingtalk-aisearch/SKILL.md +83 -0
  207. package/skills/dws/dingtalk-aisearch/references/aisearch.md +249 -0
  208. package/skills/dws/dingtalk-aisearch/references/intent-guide.md +15 -0
  209. package/skills/dws/dingtalk-aisearch/references/lite-recipes.md +31 -0
  210. package/skills/dws/dingtalk-aitable/SKILL.md +139 -0
  211. package/skills/dws/dingtalk-aitable/references/06-data-analytics.md +11 -0
  212. package/skills/dws/dingtalk-aitable/references/aitable/aitable-advperm.md +251 -0
  213. package/skills/dws/dingtalk-aitable/references/aitable/aitable-attachment.md +49 -0
  214. package/skills/dws/dingtalk-aitable/references/aitable/aitable-best-practices.md +48 -0
  215. package/skills/dws/dingtalk-aitable/references/aitable/aitable-cell-value.md +346 -0
  216. package/skills/dws/dingtalk-aitable/references/aitable/aitable-dashboard-chart.md +46 -0
  217. package/skills/dws/dingtalk-aitable/references/aitable/aitable-data-analysis-sop.md +131 -0
  218. package/skills/dws/dingtalk-aitable/references/aitable/aitable-datasource.md +272 -0
  219. package/skills/dws/dingtalk-aitable/references/aitable/aitable-error-recovery.md +128 -0
  220. package/skills/dws/dingtalk-aitable/references/aitable/aitable-export-import.md +113 -0
  221. package/skills/dws/dingtalk-aitable/references/aitable/aitable-field-properties.md +238 -0
  222. package/skills/dws/dingtalk-aitable/references/aitable/aitable-field.md +186 -0
  223. package/skills/dws/dingtalk-aitable/references/aitable/aitable-filter-sort.md +135 -0
  224. package/skills/dws/dingtalk-aitable/references/aitable/aitable-form.md +130 -0
  225. package/skills/dws/dingtalk-aitable/references/aitable/aitable-formula-guide.md +224 -0
  226. package/skills/dws/dingtalk-aitable/references/aitable/aitable-primary-doc.md +58 -0
  227. package/skills/dws/dingtalk-aitable/references/aitable/aitable-record-create.md +52 -0
  228. package/skills/dws/dingtalk-aitable/references/aitable/aitable-record-delete.md +20 -0
  229. package/skills/dws/dingtalk-aitable/references/aitable/aitable-record-history.md +97 -0
  230. package/skills/dws/dingtalk-aitable/references/aitable/aitable-record-name-key.md +47 -0
  231. package/skills/dws/dingtalk-aitable/references/aitable/aitable-record-query.md +120 -0
  232. package/skills/dws/dingtalk-aitable/references/aitable/aitable-record-share.md +54 -0
  233. package/skills/dws/dingtalk-aitable/references/aitable/aitable-record-stats.md +59 -0
  234. package/skills/dws/dingtalk-aitable/references/aitable/aitable-record-update.md +66 -0
  235. package/skills/dws/dingtalk-aitable/references/aitable/aitable-record-upsert.md +89 -0
  236. package/skills/dws/dingtalk-aitable/references/aitable/aitable-view-config.md +140 -0
  237. package/skills/dws/dingtalk-aitable/references/aitable/aitable-view-extras.md +195 -0
  238. package/skills/dws/dingtalk-aitable/references/aitable/aitable-view-types.md +95 -0
  239. package/skills/dws/dingtalk-aitable/references/aitable/aitable-workflow.md +384 -0
  240. package/skills/dws/dingtalk-aitable/references/aitable-record-ops.md +80 -0
  241. package/skills/dws/dingtalk-aitable/references/aitable-section.md +30 -0
  242. package/skills/dws/dingtalk-aitable/references/aitable.md +59 -0
  243. package/skills/dws/dingtalk-aitable/references/field-rules.md +17 -0
  244. package/skills/dws/dingtalk-aitable/references/intent-guide.md +17 -0
  245. package/skills/dws/dingtalk-aitable/references/recipes/conventions.md +44 -0
  246. package/skills/dws/dingtalk-aitable/references/url-patterns.md +144 -0
  247. package/skills/dws/dingtalk-aitable/scripts/aitable_export_via_task.py +210 -0
  248. package/skills/dws/dingtalk-aitable/scripts/aitable_import_via_task.py +173 -0
  249. package/skills/dws/dingtalk-aitable/scripts/bulk_add_fields.py +273 -0
  250. package/skills/dws/dingtalk-aitable/scripts/import_records.py +333 -0
  251. package/skills/dws/dingtalk-aitable/scripts/upload_attachment.py +190 -0
  252. package/skills/dws/dingtalk-calendar/SKILL.md +137 -0
  253. package/skills/dws/dingtalk-calendar/references/03-meeting.md +56 -0
  254. package/skills/dws/dingtalk-calendar/references/calendar.md +760 -0
  255. package/skills/dws/dingtalk-calendar/references/intent-guide.md +9 -0
  256. package/skills/dws/dingtalk-calendar/references/lite-recipes.md +25 -0
  257. package/skills/dws/dingtalk-calendar/scripts/calendar_free_slot_finder.py +199 -0
  258. package/skills/dws/dingtalk-calendar/scripts/calendar_schedule_meeting.py +233 -0
  259. package/skills/dws/dingtalk-calendar/scripts/calendar_today_agenda.py +139 -0
  260. package/skills/dws/dingtalk-chat/SKILL.md +127 -0
  261. package/skills/dws/dingtalk-chat/references/01-messaging.md +103 -0
  262. package/skills/dws/dingtalk-chat/references/card/callback.md +10 -0
  263. package/skills/dws/dingtalk-chat/references/card/create.md +27 -0
  264. package/skills/dws/dingtalk-chat/references/card/schema.md +14 -0
  265. package/skills/dws/dingtalk-chat/references/card/update.md +13 -0
  266. package/skills/dws/dingtalk-chat/references/chat/chat-bot.md +187 -0
  267. package/skills/dws/dingtalk-chat/references/chat/chat-conversation.md +165 -0
  268. package/skills/dws/dingtalk-chat/references/chat/group-admin.md +144 -0
  269. package/skills/dws/dingtalk-chat/references/chat/group-discovery.md +121 -0
  270. package/skills/dws/dingtalk-chat/references/chat/message-actions.md +132 -0
  271. package/skills/dws/dingtalk-chat/references/chat/message-media.md +76 -0
  272. package/skills/dws/dingtalk-chat/references/chat/message-query.md +135 -0
  273. package/skills/dws/dingtalk-chat/references/chat/thread.md +46 -0
  274. package/skills/dws/dingtalk-chat/references/chat-emoji-list.md +216 -0
  275. package/skills/dws/dingtalk-chat/references/chat.md +140 -0
  276. package/skills/dws/dingtalk-chat/references/contracts.md +70 -0
  277. package/skills/dws/dingtalk-chat/references/intent-guide.md +56 -0
  278. package/skills/dws/dingtalk-contact/SKILL.md +122 -0
  279. package/skills/dws/dingtalk-contact/references/08-directory.md +51 -0
  280. package/skills/dws/dingtalk-contact/references/contact.md +595 -0
  281. package/skills/dws/dingtalk-contact/references/intent-guide.md +14 -0
  282. package/skills/dws/dingtalk-contact/references/lite-recipes.md +30 -0
  283. package/skills/dws/dingtalk-contact/references/recipes/conventions.md +44 -0
  284. package/skills/dws/dingtalk-contact/scripts/contact_dept_members.py +130 -0
  285. package/skills/dws/dingtalk-doc/SKILL.md +112 -0
  286. package/skills/dws/dingtalk-doc/references/04-document.md +57 -0
  287. package/skills/dws/dingtalk-doc/references/contracts.md +40 -0
  288. package/skills/dws/dingtalk-doc/references/doc/doc-block.md +39 -0
  289. package/skills/dws/dingtalk-doc/references/doc/doc-comment.md +29 -0
  290. package/skills/dws/dingtalk-doc/references/doc/doc-create.md +54 -0
  291. package/skills/dws/dingtalk-doc/references/doc/doc-export.md +30 -0
  292. package/skills/dws/dingtalk-doc/references/doc/doc-import.md +28 -0
  293. package/skills/dws/dingtalk-doc/references/doc/doc-info.md +12 -0
  294. package/skills/dws/dingtalk-doc/references/doc/doc-media.md +46 -0
  295. package/skills/dws/dingtalk-doc/references/doc/doc-read.md +56 -0
  296. package/skills/dws/dingtalk-doc/references/doc/doc-update.md +87 -0
  297. package/skills/dws/dingtalk-doc/references/doc/format/doc-jsonml-cookbook.md +469 -0
  298. package/skills/dws/dingtalk-doc/references/doc/format/doc-jsonml-schema.json +526 -0
  299. package/skills/dws/dingtalk-doc/references/doc/format/doc-jsonml-schema.md +711 -0
  300. package/skills/dws/dingtalk-doc/references/doc/style/doc-create-workflow.md +414 -0
  301. package/skills/dws/dingtalk-doc/references/doc/style/doc-style-guideline.md +404 -0
  302. package/skills/dws/dingtalk-doc/references/doc/style/doc-update-workflow.md +316 -0
  303. package/skills/dws/dingtalk-doc/references/doc.md +82 -0
  304. package/skills/dws/dingtalk-doc/references/intent-guide.md +20 -0
  305. package/skills/dws/dingtalk-drive/SKILL.md +128 -0
  306. package/skills/dws/dingtalk-drive/references/drive.md +126 -0
  307. package/skills/dws/dingtalk-drive/references/folder-sync.md +40 -0
  308. package/skills/dws/dingtalk-drive/references/intent-guide.md +22 -0
  309. package/skills/dws/dingtalk-drive/references/lite-recipes.md +39 -0
  310. package/skills/dws/dingtalk-event/SKILL.md +106 -0
  311. package/skills/dws/dingtalk-event/references/event-im-keys.md +54 -0
  312. package/skills/dws/dingtalk-event/references/event-im-lifecycle.md +35 -0
  313. package/skills/dws/dingtalk-event/references/event-im-operations.md +52 -0
  314. package/skills/dws/dingtalk-event/references/event-im-output.md +39 -0
  315. package/skills/dws/dingtalk-event/references/event-im.md +58 -0
  316. package/skills/dws/dingtalk-event/references/event-oa.md +155 -0
  317. package/skills/dws/dingtalk-event/references/event-todo.md +50 -0
  318. package/skills/dws/dingtalk-event/references/event-voip.md +69 -0
  319. package/skills/dws/dingtalk-mail/SKILL.md +113 -0
  320. package/skills/dws/dingtalk-mail/references/09-mail.md +45 -0
  321. package/skills/dws/dingtalk-mail/references/intent-guide.md +8 -0
  322. package/skills/dws/dingtalk-mail/references/lite-recipes.md +45 -0
  323. package/skills/dws/dingtalk-mail/references/mail.md +1889 -0
  324. package/skills/dws/dingtalk-mail/references/recipes/conventions.md +44 -0
  325. package/skills/dws/dingtalk-mail/scripts/mail_send_with_cc.py +122 -0
  326. package/skills/dws/dingtalk-mail/scripts/mail_unread_summary.py +114 -0
  327. package/skills/dws/dingtalk-minutes/SKILL.md +116 -0
  328. package/skills/dws/dingtalk-minutes/references/07-minutes.md +149 -0
  329. package/skills/dws/dingtalk-minutes/references/10-minutes-speaker-match.md +32 -0
  330. package/skills/dws/dingtalk-minutes/references/11-minutes-speaker-correct.md +40 -0
  331. package/skills/dws/dingtalk-minutes/references/intent-guide.md +79 -0
  332. package/skills/dws/dingtalk-minutes/references/lite-recipes.md +25 -0
  333. package/skills/dws/dingtalk-minutes/references/minutes.md +210 -0
  334. package/skills/dws/dingtalk-minutes/references/recipes/conventions.md +33 -0
  335. package/skills/dws/dingtalk-minutes/scripts/minutes_recent_summary.py +196 -0
  336. package/skills/dws/dingtalk-minutes/scripts/test_minutes_scripts.py +222 -0
  337. package/skills/dws/dingtalk-misc/SKILL.md +55 -0
  338. package/skills/dws/dingtalk-misc/references/05-reporting.md +29 -0
  339. package/skills/dws/dingtalk-misc/references/agoal.md +302 -0
  340. package/skills/dws/dingtalk-misc/references/attendance-intent-guide.md +7 -0
  341. package/skills/dws/dingtalk-misc/references/attendance-report.md +109 -0
  342. package/skills/dws/dingtalk-misc/references/attendance-schedule.md +115 -0
  343. package/skills/dws/dingtalk-misc/references/attendance-vacation.md +129 -0
  344. package/skills/dws/dingtalk-misc/references/attendance.md +149 -0
  345. package/skills/dws/dingtalk-misc/references/dev/app.md +42 -0
  346. package/skills/dws/dingtalk-misc/references/dev/connect.md +108 -0
  347. package/skills/dws/dingtalk-misc/references/dev/credentials.md +26 -0
  348. package/skills/dws/dingtalk-misc/references/dev/dev-index.md +13 -0
  349. package/skills/dws/dingtalk-misc/references/dev/event.md +47 -0
  350. package/skills/dws/dingtalk-misc/references/dev/mcp.md +106 -0
  351. package/skills/dws/dingtalk-misc/references/dev/member.md +19 -0
  352. package/skills/dws/dingtalk-misc/references/dev/permission.md +56 -0
  353. package/skills/dws/dingtalk-misc/references/dev/recipes.md +58 -0
  354. package/skills/dws/dingtalk-misc/references/dev/robot.md +74 -0
  355. package/skills/dws/dingtalk-misc/references/dev/security.md +21 -0
  356. package/skills/dws/dingtalk-misc/references/dev/version.md +99 -0
  357. package/skills/dws/dingtalk-misc/references/dev/webapp.md +22 -0
  358. package/skills/dws/dingtalk-misc/references/devapp.md +148 -0
  359. package/skills/dws/dingtalk-misc/references/devdoc-intent-guide.md +7 -0
  360. package/skills/dws/dingtalk-misc/references/devdoc.md +42 -0
  361. package/skills/dws/dingtalk-misc/references/ding.md +184 -0
  362. package/skills/dws/dingtalk-misc/references/hrbrain.md +67 -0
  363. package/skills/dws/dingtalk-misc/references/live.md +23 -0
  364. package/skills/dws/dingtalk-misc/references/markdown.md +167 -0
  365. package/skills/dws/dingtalk-misc/references/oa/oa-form-components.md +345 -0
  366. package/skills/dws/dingtalk-misc/references/oa/oa-process-nodes.md +374 -0
  367. package/skills/dws/dingtalk-misc/references/oa.md +1014 -0
  368. package/skills/dws/dingtalk-misc/references/openapi-explorer.md +47 -0
  369. package/skills/dws/dingtalk-misc/references/pat.md +52 -0
  370. package/skills/dws/dingtalk-misc/references/profile.md +41 -0
  371. package/skills/dws/dingtalk-misc/references/recruit.md +89 -0
  372. package/skills/dws/dingtalk-misc/references/report-conventions.md +44 -0
  373. package/skills/dws/dingtalk-misc/references/report-intent-guide.md +11 -0
  374. package/skills/dws/dingtalk-misc/references/report-lite-recipes.md +25 -0
  375. package/skills/dws/dingtalk-misc/references/report.md +109 -0
  376. package/skills/dws/dingtalk-misc/references/sheet/sheet-batch-operations.md +104 -0
  377. package/skills/dws/dingtalk-misc/references/sheet/sheet-chart.md +69 -0
  378. package/skills/dws/dingtalk-misc/references/sheet/sheet-comment.md +166 -0
  379. package/skills/dws/dingtalk-misc/references/sheet/sheet-conditional-format.md +59 -0
  380. package/skills/dws/dingtalk-misc/references/sheet/sheet-dimension-operations.md +60 -0
  381. package/skills/dws/dingtalk-misc/references/sheet/sheet-dropdown.md +103 -0
  382. package/skills/dws/dingtalk-misc/references/sheet/sheet-export.md +135 -0
  383. package/skills/dws/dingtalk-misc/references/sheet/sheet-filter-view.md +51 -0
  384. package/skills/dws/dingtalk-misc/references/sheet/sheet-filter.md +181 -0
  385. package/skills/dws/dingtalk-misc/references/sheet/sheet-formula.md +192 -0
  386. package/skills/dws/dingtalk-misc/references/sheet/sheet-import.md +76 -0
  387. package/skills/dws/dingtalk-misc/references/sheet/sheet-media-image.md +263 -0
  388. package/skills/dws/dingtalk-misc/references/sheet/sheet-pivot-table.md +292 -0
  389. package/skills/dws/dingtalk-misc/references/sheet/sheet-range-operations.md +161 -0
  390. package/skills/dws/dingtalk-misc/references/sheet/sheet-read-data.md +60 -0
  391. package/skills/dws/dingtalk-misc/references/sheet/sheet-revision-changeset.md +46 -0
  392. package/skills/dws/dingtalk-misc/references/sheet/sheet-search-replace.md +120 -0
  393. package/skills/dws/dingtalk-misc/references/sheet/sheet-style-format.md +71 -0
  394. package/skills/dws/dingtalk-misc/references/sheet/sheet-version.md +84 -0
  395. package/skills/dws/dingtalk-misc/references/sheet/sheet-workbook.md +59 -0
  396. package/skills/dws/dingtalk-misc/references/sheet/sheet-write-data.md +93 -0
  397. package/skills/dws/dingtalk-misc/references/sheet-conventions.md +44 -0
  398. package/skills/dws/dingtalk-misc/references/sheet-intent-guide.md +12 -0
  399. package/skills/dws/dingtalk-misc/references/sheet.md +166 -0
  400. package/skills/dws/dingtalk-misc/references/skill.md +98 -0
  401. package/skills/dws/dingtalk-misc/references/unsupported-scripts.md +49 -0
  402. package/skills/dws/dingtalk-misc/references/url-patterns.md +144 -0
  403. package/skills/dws/dingtalk-misc/references/whiteboard/compose.md +200 -0
  404. package/skills/dws/dingtalk-misc/references/whiteboard/open-nodes-v1/01-overview.md +57 -0
  405. package/skills/dws/dingtalk-misc/references/whiteboard/open-nodes-v1/02-query.md +288 -0
  406. package/skills/dws/dingtalk-misc/references/whiteboard/open-nodes-v1/03-update.md +249 -0
  407. package/skills/dws/dingtalk-misc/references/whiteboard/open-nodes-v1/04-text-style.md +395 -0
  408. package/skills/dws/dingtalk-misc/references/whiteboard/open-nodes-v1/05-shape-frame-group-connector.md +186 -0
  409. package/skills/dws/dingtalk-misc/references/whiteboard/open-nodes-v1/06-vector-icon-path.md +313 -0
  410. package/skills/dws/dingtalk-misc/references/whiteboard/open-nodes-v1/07-examples-errors-write-support.md +270 -0
  411. package/skills/dws/dingtalk-misc/references/whiteboard/open-nodes-v1/08-catalogs.md +61 -0
  412. package/skills/dws/dingtalk-misc/references/whiteboard/open-nodes-v1.md +54 -0
  413. package/skills/dws/dingtalk-misc/references/whiteboard/replace.md +41 -0
  414. package/skills/dws/dingtalk-misc/references/whiteboard/vector.md +51 -0
  415. package/skills/dws/dingtalk-misc/references/whiteboard.md +115 -0
  416. package/skills/dws/dingtalk-misc/scripts/aiapp_create_and_poll.py +138 -0
  417. package/skills/dws/dingtalk-misc/scripts/attendance_my_record.py +91 -0
  418. package/skills/dws/dingtalk-misc/scripts/attendance_report_checkin.py +440 -0
  419. package/skills/dws/dingtalk-misc/scripts/attendance_report_common.py +1698 -0
  420. package/skills/dws/dingtalk-misc/scripts/attendance_report_daily.py +558 -0
  421. package/skills/dws/dingtalk-misc/scripts/attendance_report_detail.py +809 -0
  422. package/skills/dws/dingtalk-misc/scripts/attendance_report_monthly.py +758 -0
  423. package/skills/dws/dingtalk-misc/scripts/attendance_report_record.py +947 -0
  424. package/skills/dws/dingtalk-misc/scripts/attendance_schedule_export.py +344 -0
  425. package/skills/dws/dingtalk-misc/scripts/attendance_schedule_import.py +498 -0
  426. package/skills/dws/dingtalk-misc/scripts/attendance_team_shift.py +89 -0
  427. package/skills/dws/dingtalk-misc/scripts/attendance_vacation_balance.py +617 -0
  428. package/skills/dws/dingtalk-misc/scripts/finance_daily_cashflow.py +70 -0
  429. package/skills/dws/dingtalk-misc/scripts/finance_expense_flow.py +138 -0
  430. package/skills/dws/dingtalk-misc/scripts/oa_batch_approve.py +158 -0
  431. package/skills/dws/dingtalk-misc/scripts/oa_pending_review.py +132 -0
  432. package/skills/dws/dingtalk-misc/scripts/report_received_today.py +315 -0
  433. package/skills/dws/dingtalk-misc/scripts/yida_custom_page_update.py +401 -0
  434. package/skills/dws/dingtalk-misc/scripts/yida_form_builder.py +526 -0
  435. package/skills/dws/dingtalk-misc/scripts/yida_form_fields.py +315 -0
  436. package/skills/dws/dingtalk-misc/scripts/yida_form_inspector.py +311 -0
  437. package/skills/dws/dingtalk-misc/scripts/yida_form_update.py +185 -0
  438. package/skills/dws/dingtalk-misc/scripts/yida_jsx_pipeline.py +1588 -0
  439. package/skills/dws/dingtalk-misc/scripts/yida_page_compiler.py +1441 -0
  440. package/skills/dws/dingtalk-misc/scripts/yida_page_generate.py +514 -0
  441. package/skills/dws/dingtalk-misc/scripts/yida_page_schema.py +519 -0
  442. package/skills/dws/dingtalk-misc/scripts/yida_page_self_check.py +398 -0
  443. package/skills/dws/dingtalk-misc/scripts/yida_process_flow.py +1478 -0
  444. package/skills/dws/dingtalk-misc/scripts/yida_process_update.py +589 -0
  445. package/skills/dws/dingtalk-misc/scripts/yida_report_builder.py +494 -0
  446. package/skills/dws/dingtalk-misc/scripts/yida_report_charts.py +1434 -0
  447. package/skills/dws/dingtalk-misc/scripts/yida_report_update.py +244 -0
  448. package/skills/dws/dingtalk-misc/scripts/yida_schema_common.py +340 -0
  449. package/skills/dws/dingtalk-shared/SKILL.md +83 -0
  450. package/skills/dws/dingtalk-shared/references/capability-limits.md +31 -0
  451. package/skills/dws/dingtalk-shared/references/channel-login.md +26 -0
  452. package/skills/dws/dingtalk-shared/references/confirmation.md +59 -0
  453. package/skills/dws/dingtalk-shared/references/error-codes.md +155 -0
  454. package/skills/dws/dingtalk-shared/references/global-reference.md +122 -0
  455. package/skills/dws/dingtalk-shared/references/intent-guide.md +537 -0
  456. package/skills/dws/dingtalk-shared/references/recipes/conventions.md +45 -0
  457. package/skills/dws/dingtalk-shared/references/recipes/lite-catalog.md +275 -0
  458. package/skills/dws/dingtalk-shared/references/recipes/meta.md +67 -0
  459. package/skills/dws/dingtalk-shared/references/routing.md +52 -0
  460. package/skills/dws/dingtalk-shared/references/runtime-contract.md +11 -0
  461. package/skills/dws/dingtalk-shared/references/schema-usage.md +88 -0
  462. package/skills/dws/dingtalk-shared/references/url-patterns.md +144 -0
  463. package/skills/dws/dingtalk-shared/references/workflow-routing.md +45 -0
  464. package/skills/dws/dingtalk-todo/SKILL.md +119 -0
  465. package/skills/dws/dingtalk-todo/references/02-task.md +70 -0
  466. package/skills/dws/dingtalk-todo/references/intent-guide.md +15 -0
  467. package/skills/dws/dingtalk-todo/references/lite-recipes.md +68 -0
  468. package/skills/dws/dingtalk-todo/references/recipes/conventions.md +44 -0
  469. package/skills/dws/dingtalk-todo/references/todo.md +517 -0
  470. package/skills/dws/dingtalk-todo/scripts/todo_batch_create.py +354 -0
  471. package/skills/dws/dingtalk-todo/scripts/todo_daily_summary.py +153 -0
  472. package/skills/dws/dingtalk-todo/scripts/todo_overdue_check.py +101 -0
  473. package/skills/dws/dingtalk-wiki/SKILL.md +117 -0
  474. package/skills/dws/dingtalk-wiki/references/intent-guide.md +14 -0
  475. package/skills/dws/dingtalk-wiki/references/lite-recipes.md +44 -0
  476. package/skills/dws/dingtalk-wiki/references/wiki-members.md +32 -0
  477. package/skills/dws/dingtalk-wiki/references/wiki-node-ops.md +46 -0
  478. package/skills/dws/dingtalk-wiki/references/wiki.md +65 -0
  479. package/skills/dws/provenance.json +27 -0
@@ -0,0 +1,1434 @@
1
+ """
2
+ 宜搭报表图表组件构造 — 按 chart.type 分发,产出 component dict + cube 查询模型。
3
+
4
+ 支持 9 种图表: bar / line / pie / funnel / table / indicator / gauge / combo / pivot
5
+
6
+ dataSetModelMap 结构严格匹配宜搭报表引擎格式:
7
+ - 外层 key: chartData (bar/line/pie/funnel/gauge) / table / youshuData (indicator)
8
+ / dataSetName (combo/pivot)
9
+ - 内层: dataViewQueryModel{cubeCode, fieldDefinitionList, fieldList, cubeTenantId}
10
+ + 外层 fieldList (完整字段对象) + xField/yField 等角色字段
11
+ """
12
+ from __future__ import annotations
13
+
14
+ import math
15
+ from typing import Any, Optional
16
+
17
+ from yida_schema_common import (
18
+ i18n,
19
+ next_node_id,
20
+ generate_field_id,
21
+ )
22
+
23
+ # ---------------------------------------------------------------------------
24
+ # 图表类型 → componentName 映射
25
+ # ---------------------------------------------------------------------------
26
+
27
+ CHART_TYPE_MAP: dict[str, str] = {
28
+ "bar": "YoushuGroupedBarChart",
29
+ "line": "YoushuLineChart",
30
+ "pie": "YoushuPieChart",
31
+ "funnel": "YoushuFunnelChart",
32
+ "table": "YoushuTable",
33
+ "indicator": "YoushuSimpleIndicatorCard",
34
+ "gauge": "YoushuGauge",
35
+ "combo": "YoushuComboChart",
36
+ "pivot": "YoushuCrossPivotTable",
37
+ }
38
+
39
+ def _compute_dynamic_layout(chart_type: str, chart: dict[str, Any]) -> dict[str, Any]:
40
+ """根据图表内容动态计算布局尺寸。"""
41
+ if chart_type == "table":
42
+ page_size = chart.get("pageSize", 20)
43
+ h = max(16, min(40, round(page_size * 0.9) + 6))
44
+ return {"w": 6, "h": h, "minH": h, "maxH": h, "resizeHandles": ["w", "e"]}
45
+
46
+ if chart_type == "indicator":
47
+ kpi_count = len(chart.get("kpi", []))
48
+ col = min(kpi_count, 4) or 1
49
+ rows = math.ceil(kpi_count / col)
50
+ h = max(11, 8 + rows * 5)
51
+ w = min(2 * min(kpi_count, 3), 6)
52
+ return {"w": w, "h": h, "minH": h, "maxH": h, "resizeHandles": ["w", "e"]}
53
+
54
+ if chart_type in ("bar", "line"):
55
+ y_raw = chart.get("yField", "")
56
+ y_count = len(y_raw) if isinstance(y_raw, list) else 1
57
+ h = 22 if y_count <= 3 else min(30, 22 + (y_count - 3) * 2)
58
+ return {"w": 3, "h": h}
59
+
60
+ if chart_type == "gauge":
61
+ return {"w": 2, "h": 18}
62
+
63
+ if chart_type == "combo":
64
+ return {"w": 6, "h": 22}
65
+
66
+ if chart_type == "pivot":
67
+ return {"w": 6, "h": 30}
68
+
69
+ return {"w": 3, "h": 22}
70
+
71
+ _VALUE_SUFFIX_PREFIXES = ("selectField_", "radioField_", "checkboxField_", "multiSelectField_", "employeeField_")
72
+
73
+ _CUBE_LABEL_SUFFIX: dict[str, str] = {
74
+ "selectField_": "_值",
75
+ "radioField_": "_值",
76
+ "checkboxField_": "_值",
77
+ "multiSelectField_": "_值",
78
+ "employeeField_": "_名称",
79
+ "departmentSelectField_": "_名称",
80
+ }
81
+
82
+ _DS_KEY_CHART = "chartData"
83
+ _DS_KEY_TABLE = "table"
84
+ _DS_KEY_INDICATOR = "youshuData"
85
+ _DS_KEY_DATASET = "dataSetName"
86
+
87
+ _TIME_GRAN_ID_SUFFIX: dict[str, str] = {
88
+ "YEAR": "1", "QUARTER": "2", "MONTH": "3",
89
+ "WEEK": "4", "DAY": "5", "HOUR": "6",
90
+ }
91
+ _TIME_GRAN_FORMAT: dict[str, str] = {
92
+ "YEAR": "yyyy", "QUARTER": "yyyy-Q", "MONTH": "yyyy-MM",
93
+ "WEEK": "yyyy-w", "DAY": "yyyy-MM-dd", "HOUR": "yyyy-MM-dd HH",
94
+ }
95
+
96
+ _AGGREGATE_TYPES = frozenset({"COUNT", "SUM", "AVG", "MAX", "MIN", "COUNT_DISTINCT"})
97
+
98
+
99
+ # ---------------------------------------------------------------------------
100
+ # 公共工具
101
+ # ---------------------------------------------------------------------------
102
+
103
+
104
+ def normalize_cube_code(code: str) -> str:
105
+ """FORM-E604838A-3121-43D1-... → FORM_E604838A312143D1..."""
106
+ if code.startswith(("FORM-", "FORM_")):
107
+ return "FORM_" + code[5:].replace("-", "")
108
+ return code.replace("-", "_")
109
+
110
+
111
+ _STRIP_SUFFIXES = ("_id", "_date")
112
+
113
+
114
+ def normalize_field_code(field_code: str) -> str:
115
+ fc = field_code
116
+ for sfx in _STRIP_SUFFIXES:
117
+ if fc.endswith(sfx):
118
+ fc = fc[:-len(sfx)]
119
+ break
120
+ if any(fc.startswith(p) for p in _VALUE_SUFFIX_PREFIXES):
121
+ if not fc.endswith("_value"):
122
+ return fc + "_value"
123
+ return fc
124
+
125
+
126
+ def _apply_cube_label_suffix(field_code: str, text: str) -> str:
127
+ """fieldCode 带 _value 后缀时,同步给显示标签追加中文后缀。
128
+
129
+ cube 元数据中 selectField_xxx_value 显示名为 "原标签_值",
130
+ employeeField_xxx_value 显示名为 "原标签_名称"。
131
+ 不追加会导致引擎报"找不到配置"。
132
+ """
133
+ if not field_code.endswith("_value"):
134
+ return text
135
+ base = field_code[:-6]
136
+ for prefix, suffix in _CUBE_LABEL_SUFFIX.items():
137
+ if base.startswith(prefix):
138
+ if not text.endswith(suffix):
139
+ return text + suffix
140
+ return text
141
+ return text
142
+
143
+
144
+ def _derive_label(field_code: str) -> str:
145
+ """从 fieldCode 推导可读标签:去前缀、去 _value 后缀。"""
146
+ fc = field_code
147
+ for p in _VALUE_SUFFIX_PREFIXES:
148
+ if fc.startswith(p):
149
+ fc = fc[len(p):]
150
+ break
151
+ else:
152
+ for prefix in ("textField_", "numberField_", "dateField_", "textareaField_",
153
+ "countrySelectField_", "addressField_", "attachmentField_",
154
+ "imageField_", "departmentSelectField_", "tableField_",
155
+ "associationFormField_", "serialNumberField_", "rateField_",
156
+ "cascadeDateField_"):
157
+ if fc.startswith(prefix):
158
+ fc = fc[len(prefix):]
159
+ break
160
+ if fc.endswith("_value"):
161
+ fc = fc[:-6]
162
+ return fc or field_code
163
+
164
+
165
+ def _infer_data_type(field_code: str) -> str:
166
+ if field_code.startswith("numberField_"):
167
+ return "NUMBER"
168
+ if field_code.startswith("dateField_"):
169
+ return "DATE"
170
+ if field_code.startswith(("employeeField_", "departmentSelectField_")):
171
+ return "STRING" if field_code.endswith("_value") else "ARRAY"
172
+ return "STRING"
173
+
174
+
175
+ _ARRAY_FIELD_PREFIXES = ("employeeField_", "departmentSelectField_")
176
+
177
+
178
+ def _fix_array_field_for_aggregate(field_code: str, data_type: str, aggregate_type: str) -> tuple[str, str]:
179
+ """数组字段做聚合时保留 _value 后缀(cube 元数据只认 _value),仅将 ARRAY 类型转为 STRING。"""
180
+ if aggregate_type == "NONE":
181
+ return field_code, data_type
182
+ if any(field_code.startswith(p) for p in _ARRAY_FIELD_PREFIXES):
183
+ import warnings
184
+ warnings.warn(
185
+ f"⚠ {field_code} 是数组字段,不能做聚合({aggregate_type})——"
186
+ f"cube SQL 会报 'aggregate cannot contain set-returning function'。"
187
+ f"请改用非数组字段(如 numberField / textField)做 {aggregate_type}。",
188
+ stacklevel=3,
189
+ )
190
+ if data_type == "ARRAY":
191
+ return field_code, "STRING"
192
+ return field_code, data_type
193
+
194
+
195
+ def _is_date_field(field_code: str) -> bool:
196
+ return field_code.startswith("dateField_")
197
+
198
+
199
+ def _gen_alias() -> str:
200
+ return f"field_{next_node_id()}"
201
+
202
+
203
+ # ---------------------------------------------------------------------------
204
+ # 字段解析:支持 string 或 rich field dict
205
+ # ---------------------------------------------------------------------------
206
+
207
+
208
+ def _resolve_field(raw: Any, cube_code: str) -> dict[str, Any]:
209
+ """把 string 或 dict 输入统一解析为标准字段元数据。"""
210
+ if isinstance(raw, dict):
211
+ fc = normalize_field_code(raw.get("fieldCode", ""))
212
+ if not fc:
213
+ raise ValueError(
214
+ f"fieldCode 不能为空。请先通过 `dws yida form components` 获取源表字段定义,"
215
+ f"使用返回的 fieldCode 构造字段对象。收到: {raw!r}"
216
+ )
217
+ text = raw.get("text") or raw.get("label") or _derive_label(fc)
218
+ text = _apply_cube_label_suffix(fc, text)
219
+ return {
220
+ "fieldCode": fc,
221
+ "dataType": raw.get("dataType") or _infer_data_type(fc),
222
+ "text": text,
223
+ "id": raw.get("id") or fc,
224
+ "classifiedCode": raw.get("classifiedCode") or cube_code,
225
+ "timeGranularityType": raw.get("timeGranularityType"),
226
+ "timeFormat": raw.get("timeFormat"),
227
+ }
228
+ fc = normalize_field_code(str(raw))
229
+ if not fc:
230
+ raise ValueError(
231
+ "fieldCode 不能为空字符串。请先通过 `dws yida form components` 获取源表字段定义。"
232
+ )
233
+ text = _apply_cube_label_suffix(fc, _derive_label(fc))
234
+ return {
235
+ "fieldCode": fc,
236
+ "dataType": _infer_data_type(fc),
237
+ "text": text,
238
+ "id": fc,
239
+ "classifiedCode": cube_code,
240
+ "timeGranularityType": None,
241
+ "timeFormat": None,
242
+ }
243
+
244
+
245
+ # ---------------------------------------------------------------------------
246
+ # 字段对象构造(匹配宜搭报表引擎格式)
247
+ # ---------------------------------------------------------------------------
248
+
249
+
250
+ def _build_query_field_def(
251
+ alias: str,
252
+ label: str,
253
+ cube_code: str,
254
+ field_code: str,
255
+ data_type: str,
256
+ aggregate_type: str = "NONE",
257
+ time_gran: Optional[str] = None,
258
+ classified_code: Optional[str] = None,
259
+ ) -> dict[str, Any]:
260
+ """dataViewQueryModel.fieldDefinitionList 中的单条定义。"""
261
+ return {
262
+ "classifiedCode": classified_code or cube_code,
263
+ "cubeCode": cube_code,
264
+ "fieldCode": field_code,
265
+ "dataType": data_type,
266
+ "isDim": False,
267
+ "aggregateType": aggregate_type,
268
+ "alias": alias,
269
+ "aliasName": {"type": "i18n", "zh_CN": label, "en_US": label},
270
+ "timeGranularityType": time_gran,
271
+ }
272
+
273
+
274
+ def _build_full_field(
275
+ alias: str,
276
+ label: str,
277
+ cube_code: str,
278
+ field_code: str,
279
+ data_type: str,
280
+ aggregate_type: str = "NONE",
281
+ time_gran: Optional[str] = None,
282
+ classified_code: Optional[str] = None,
283
+ field_id: Optional[str] = None,
284
+ time_format: Optional[str] = None,
285
+ ) -> dict[str, Any]:
286
+ """外层 fieldList / xField / yField 中的完整字段对象。"""
287
+ fid = field_id or field_code
288
+ effective_dt = "DOUBLE" if aggregate_type in _AGGREGATE_TYPES else data_type
289
+ result: dict[str, Any] = {
290
+ "title": i18n(label),
291
+ "classifiedCode": classified_code or cube_code,
292
+ "cubeCode": cube_code,
293
+ "fieldCode": field_code,
294
+ "isDimension": "false",
295
+ "dataType": effective_dt,
296
+ "format": {"type": "NONE"},
297
+ "link": [{"type": "NONE"}],
298
+ "drillList": [],
299
+ "aggregateType": aggregate_type,
300
+ "orderBy": {"type": "NONE", "reference": alias},
301
+ "fieldKey": alias,
302
+ "visible": True,
303
+ "beUsedTimes": 1,
304
+ "isVisible": "y",
305
+ "id": fid,
306
+ "text": label,
307
+ }
308
+ if aggregate_type in _AGGREGATE_TYPES:
309
+ result["measureType"] = "MEASURE_ATTRIBUTE"
310
+ if time_gran:
311
+ result["timeGranularityType"] = time_gran
312
+ suffix = _TIME_GRAN_ID_SUFFIX.get(time_gran, "")
313
+ if suffix:
314
+ result["id"] = field_code + suffix
315
+ fmt = time_format or _TIME_GRAN_FORMAT.get(time_gran)
316
+ if fmt:
317
+ result["timeFormat"] = fmt
318
+ return result
319
+
320
+
321
+ def _wrap_dataset(
322
+ ds_key: str,
323
+ cube_code: str,
324
+ cube_tenant_id: str,
325
+ query_field_defs: list[dict[str, Any]],
326
+ aliases: list[str],
327
+ full_fields: list[dict[str, Any]],
328
+ extra: Optional[dict[str, Any]] = None,
329
+ extra_query: Optional[dict[str, Any]] = None,
330
+ ) -> dict[str, Any]:
331
+ """组装完整 dataSetModelMap(匹配宜搭报表引擎结构)。"""
332
+ query_model: dict[str, Any] = {
333
+ "cubeCode": cube_code,
334
+ "cubeTenantId": cube_tenant_id,
335
+ "fieldDefinitionList": query_field_defs,
336
+ "fieldList": aliases,
337
+ "filterList": [],
338
+ "orderByList": [],
339
+ }
340
+ if extra_query:
341
+ query_model.update(extra_query)
342
+
343
+ ds: dict[str, Any] = {
344
+ "cubeCodes": [cube_code],
345
+ "dataViewQueryModel": query_model,
346
+ "fieldList": full_fields,
347
+ "youshuDataType": "real",
348
+ "filterList": [],
349
+ "limit": "",
350
+ "mockData": [],
351
+ }
352
+
353
+ if extra:
354
+ ds.update(extra)
355
+ return {ds_key: ds}
356
+
357
+
358
+ # ---------------------------------------------------------------------------
359
+ # 图表 settings 默认值
360
+ # ---------------------------------------------------------------------------
361
+
362
+ _AXIS_LABEL_STYLE = {
363
+ "labelType": "default",
364
+ "color": "rgba(23,26,29,0.4)",
365
+ "fontSize": 12,
366
+ "limitLengthType": "percent",
367
+ "percent": 30,
368
+ "value": 100,
369
+ "autoRotate": True,
370
+ "rotate": "0",
371
+ "autoHide": True,
372
+ }
373
+
374
+ _X_AXIS_DEFAULT = {
375
+ "showXAxis": True,
376
+ "showTitle": False,
377
+ "title": {"type": "i18n", "zh_CN": "", "en_US": ""},
378
+ "line": True,
379
+ "tickLine": True,
380
+ "grid": False,
381
+ "label": True,
382
+ "labelStyle": _AXIS_LABEL_STYLE,
383
+ "values": {"type": "i18n", "zh_CN": "", "en_US": ""},
384
+ }
385
+
386
+ _Y_AXIS_DEFAULT = {
387
+ "showYAxis": True,
388
+ "showTitle": False,
389
+ "title": {"type": "i18n", "zh_CN": "", "en_US": ""},
390
+ "line": False,
391
+ "tickLine": False,
392
+ "grid": True,
393
+ "label": True,
394
+ "labelStyle": _AXIS_LABEL_STYLE,
395
+ "min": None,
396
+ "max": None,
397
+ "tickCount": 5,
398
+ }
399
+
400
+ _CUSTOM_COLOR = "#5894FF,#394B76,#F7B900,#E55F24,#80D5F5,#9849B0,#3BC88A,#0E869D,#F4A49E,#80563C"
401
+
402
+ _LEGEND_DEFAULT = {"showLegend": True, "legendPosition": "top-left", "flipPage": True}
403
+
404
+
405
+ def _get_chart_settings(chart_type: str, chart: dict[str, Any]) -> dict[str, Any]:
406
+ if chart_type == "bar":
407
+ return {
408
+ "container": {"height": 248},
409
+ "style": {
410
+ "mode": "group",
411
+ "linkGroup": False,
412
+ "transpose": False,
413
+ "barStyle": "ai",
414
+ "size": None,
415
+ "maxSize": None,
416
+ "minSize": None,
417
+ "barBackground": None,
418
+ "groupSpacing": 0,
419
+ "radiusLeftTop": 4,
420
+ "radiusRightTop": 4,
421
+ "radiusRightBottom": 0,
422
+ "radiusLeftBottom": 0,
423
+ "colorType": "CUSTOM_COLOR",
424
+ "chartColorsMode": "EHRColorsMode",
425
+ "customColor": _CUSTOM_COLOR,
426
+ },
427
+ "countLabel": {"showCountLabel": False, "fontSize": 12, "color": "#000"},
428
+ "axisType": "hz",
429
+ "xAxis": _X_AXIS_DEFAULT,
430
+ "yAxis": _Y_AXIS_DEFAULT,
431
+ "legend": _LEGEND_DEFAULT,
432
+ "label": {
433
+ "showLabel": True,
434
+ "labelShowStyle": "ai",
435
+ "fontSize": 12,
436
+ "autoColor": True,
437
+ "color": "#000",
438
+ "autoPosition": False,
439
+ "position": "middle",
440
+ "autoAdjust": True,
441
+ "autoHide": True,
442
+ },
443
+ "slider": {"showSlider": False},
444
+ "tooltip": {"showTooltip": True},
445
+ }
446
+ elif chart_type == "line":
447
+ return {
448
+ "container": {"height": 248},
449
+ "style": {
450
+ "mode": "none",
451
+ "lineStyle": "ai",
452
+ "lineSize": 2,
453
+ "smooth": False,
454
+ "showArea": False,
455
+ "areaOpacity": 0.25,
456
+ "showPoint": True,
457
+ "pointSize": 4,
458
+ "pointShape": "circle",
459
+ "showLine": True,
460
+ "lineWidth": 2,
461
+ "colorType": "CUSTOM_COLOR",
462
+ "chartColorsMode": "EHRColorsMode",
463
+ "customColor": _CUSTOM_COLOR,
464
+ },
465
+ "axisType": "hz",
466
+ "xAxis": _X_AXIS_DEFAULT,
467
+ "yAxis": _Y_AXIS_DEFAULT,
468
+ "legend": _LEGEND_DEFAULT,
469
+ "label": {"showLabel": True, "fontSize": 12, "color": "#000", "autoOverlap": True},
470
+ "slider": {"showSlider": False},
471
+ "tooltip": {"showTooltip": True},
472
+ }
473
+ elif chart_type == "pie":
474
+ return {
475
+ "container": {"height": 248},
476
+ "style": {
477
+ "radius": 75,
478
+ "isRing": False,
479
+ "innerRadius": 0,
480
+ "colorType": "CUSTOM_COLOR",
481
+ "chartColorsMode": "EHRColorsMode",
482
+ "customColor": _CUSTOM_COLOR,
483
+ },
484
+ "statistic": {"showStatistic": False},
485
+ "label": {
486
+ "showLabel": True,
487
+ "showLine": True,
488
+ "labelAlign": "outer",
489
+ "labelSize": 12,
490
+ "labelColor": "#404040",
491
+ "labelFormatType": "NAME_PERCENT",
492
+ },
493
+ "legend": {
494
+ "showLegend": True,
495
+ "legendPosition": "right",
496
+ "flipPage": True,
497
+ "type": "item",
498
+ "contentType": "NAME",
499
+ "cardWidth": None,
500
+ "ratio": 65,
501
+ "layout": "vertical",
502
+ "itemSpacing": 12,
503
+ },
504
+ "tooltip": {"showTooltip": True, "contentType": None},
505
+ "percentDigits": 2,
506
+ }
507
+ elif chart_type == "funnel":
508
+ return {
509
+ "container": {"height": 248},
510
+ "style": {
511
+ "colorType": "CUSTOM_COLOR",
512
+ "chartColorsMode": "EHRColorsMode",
513
+ "customColor": _CUSTOM_COLOR,
514
+ },
515
+ "legend": _LEGEND_DEFAULT,
516
+ "label": {"showLabel": True, "fontSize": 12, "color": "#000"},
517
+ "tooltip": {"showTooltip": True},
518
+ }
519
+ elif chart_type == "gauge":
520
+ return {
521
+ "container": {"height": 248},
522
+ "useSingleColor": False,
523
+ "singleColor": "#0089FF",
524
+ "color": [],
525
+ "tick": {"showTick": True, "min": None, "max": None, "tickInterval": None},
526
+ "assistValue": {"openAssistValue": True, "showCompare": False, "position": "bottom"},
527
+ "style": {"rounded": True, "pivot": True, "rangeSize": 16, "radius": 95, "innerRadius": 90},
528
+ }
529
+ elif chart_type == "combo":
530
+ return {
531
+ "container": {"height": 248},
532
+ "style": {
533
+ "sync": False,
534
+ "chartType": "bar-line",
535
+ "bar": {
536
+ "size": None, "maxSize": None, "minSize": None, "mode": "group",
537
+ "barBackground": None,
538
+ "radiusLeftTop": 4, "radiusRightTop": 4,
539
+ "radiusRightBottom": 0, "radiusLeftBottom": 0,
540
+ },
541
+ "line": {
542
+ "size": 2, "smooth": False,
543
+ "showPoint": True, "pointSize": 4, "pointShape": "circle",
544
+ },
545
+ "autoAdjust": True,
546
+ "colorType": "CUSTOM_COLOR",
547
+ "chartColorsMode": "EHRColorsMode",
548
+ "customColor": _CUSTOM_COLOR,
549
+ },
550
+ "xAxis": _X_AXIS_DEFAULT,
551
+ "leftYAxis": {
552
+ "showLeftYAxis": True, "showTitle": False,
553
+ "title": {"type": "i18n", "zh_CN": "", "en_US": ""},
554
+ "line": False, "tickLine": False, "grid": True, "label": True,
555
+ "labelStyle": _AXIS_LABEL_STYLE,
556
+ "min": None, "max": None, "tickCount": 5,
557
+ },
558
+ "rightYAxis": {
559
+ "showRightYAxis": True, "showTitle": False,
560
+ "title": {"type": "i18n", "zh_CN": "", "en_US": ""},
561
+ "line": False, "tickLine": False, "grid": False, "label": True,
562
+ "labelStyle": _AXIS_LABEL_STYLE,
563
+ "min": None, "max": None, "tickCount": 5,
564
+ },
565
+ "legend": _LEGEND_DEFAULT,
566
+ "leftLabel": {"showLabel": True, "fontSize": 12, "color": "#000"},
567
+ "rightLabel": {"showLabel": True, "fontSize": 12, "color": "#000"},
568
+ "slider": {"showSlider": False},
569
+ "tooltip": {"showTooltip": True},
570
+ }
571
+ elif chart_type == "table":
572
+ page_size = chart.get("pageSize", 20)
573
+ return {
574
+ "rglConfig": {"w": 6, "h": 21, "isHeightAuto": True},
575
+ "size": "medium",
576
+ "wordSize": "medium:14",
577
+ "theme": "split",
578
+ "mergeCell": False,
579
+ "fixedHeader": False,
580
+ "maxBodyHeight": "300",
581
+ "fixedColumnIndex": 1,
582
+ "isReverseTable": False,
583
+ "showReversedHeader": False,
584
+ "isUniqueRows": False,
585
+ "pagination": {
586
+ "isPagination": True,
587
+ "pageSize": page_size,
588
+ "pageShowCount": 5,
589
+ "showPageSelect": False,
590
+ "size": "small",
591
+ "type": "normal",
592
+ },
593
+ "isTree": False,
594
+ "idField": None,
595
+ "pidField": None,
596
+ "isLeaf": None,
597
+ "drilldownFilterList": None,
598
+ "defaultExpand": False,
599
+ "rankStyle": False,
600
+ "container": {"height": 472},
601
+ "titleTip": False,
602
+ "showCopyData": False,
603
+ "enableFieldSelect": False,
604
+ "defaultSelectedFields": "",
605
+ "hasFullscreen": False,
606
+ "copyAsImg": False,
607
+ "height": None,
608
+ "isHeightAuto": True,
609
+ }
610
+ elif chart_type == "indicator":
611
+ kpi_count = len(chart.get("kpi", []))
612
+ return {
613
+ "showSideStyle": "NONE",
614
+ "followTheme": False,
615
+ "themeType": "dark",
616
+ "showSideBorder": True,
617
+ "sideBarColor": "#0089FF",
618
+ "bgColorType": "single",
619
+ "singleBgColor": "#F1F2F3",
620
+ "colorType": "SCHEMA_COLOR",
621
+ "multipleBgColor": "defaultColorsMode",
622
+ "customColor": "#0089FF,#FF9200,#11AB4F,#FFD100,#7263EE,#67C5EB,#6B748C,#FF755A,#007E99,#FFA8A8",
623
+ "size": "normal",
624
+ "valueSize": "20px",
625
+ "titleMaxRow": 0,
626
+ "columnCount": min(kpi_count, 4) or 4,
627
+ "columnCountForH5": min(kpi_count, 2) or 2,
628
+ "popoverAlign": "b",
629
+ "container": {"height": 72},
630
+ "titleTip": False,
631
+ "enableFieldSelect": False,
632
+ "hasFullscreen": False,
633
+ "copyAsImg": False,
634
+ "height": None,
635
+ "isHeightAuto": True,
636
+ }
637
+ elif chart_type == "pivot":
638
+ return {
639
+ "rglConfig": {"w": 6, "h": 21, "isHeightAuto": True},
640
+ "maxBodyHeight": 500,
641
+ "size": "normal",
642
+ "rows": [],
643
+ "columns": [],
644
+ "measures": [],
645
+ "details": [],
646
+ "supportExport": False,
647
+ "exportType": "XJZ",
648
+ "dialogWidth": 850,
649
+ "dialogPageSize": 10,
650
+ "baseInfo": {
651
+ "isShowSetter": True, "isShowFilter": False, "isShowReload": False,
652
+ "isHideTitle": False, "isMeasureOrder": True, "isZebra": True,
653
+ "rowMaxSize": 3000, "columnsMaxSize": 500, "columnWidth": 100,
654
+ "dialogWidth": 850, "dialogPageSize": 10,
655
+ "detailExportData": {"supportExport": False, "exportType": "BROWSER"},
656
+ },
657
+ "mode": "summary",
658
+ "summaryInfo": {
659
+ "isRowTotal": True, "rowTotalWidth": 130, "rowTotalPosition": "end",
660
+ "isColumnTotal": True, "isSubTotal": False,
661
+ "rowMaxSize": 3000, "columnsMaxSize": 500,
662
+ },
663
+ "paginationInfo": {
664
+ "size": "small", "type": "normal", "pageShowCount": 5,
665
+ "pageSize": 10, "showPageSelect": False,
666
+ },
667
+ "container": {"height": 232},
668
+ "titleTip": False,
669
+ "hasFullscreen": False,
670
+ "copyAsImg": False,
671
+ "height": None,
672
+ "isHeightAuto": True,
673
+ }
674
+ return {}
675
+
676
+
677
+ # ---------------------------------------------------------------------------
678
+ # userConfig 构建(设计器数据配置面板)
679
+ # ---------------------------------------------------------------------------
680
+
681
+ def _setter(name: str, title: str, **extra_props: Any) -> dict[str, Any]:
682
+ item: dict[str, Any] = {"setterName": "ColumnFieldSetter", "name": name, "title": title}
683
+ if extra_props:
684
+ item["setterProps"] = extra_props
685
+ return item
686
+
687
+
688
+ def _build_user_config(chart_type: str) -> list[dict[str, Any]]:
689
+ if chart_type in ("bar", "line"):
690
+ return [{"name": _DS_KEY_CHART, "title": "配置数据", "items": [
691
+ _setter("xField", "横轴", single=True, showFormatTab=True, showFormulaEditor=True,
692
+ showFieldInfo=True, showAggregateTab=False, showDrillTab=True, showEditTab=True, showSortTab=True),
693
+ _setter("yField", "纵轴", showFormatTab=True, showFormulaEditor=True,
694
+ showFieldInfo=True, showEditTab=True, showSortTab=True, showDataLink=True),
695
+ _setter("groupField", "分组", single=True, showFormatTab=True, showEditTab=True),
696
+ _setter("annotationField", "参考线", showFormatTab=True, showEditTab=True),
697
+ ]}]
698
+ if chart_type == "pie":
699
+ return [{"name": _DS_KEY_CHART, "title": "配置数据", "items": [
700
+ _setter("xField", "分类字段", single=True, showAggregateTab=False, showDrillTab=True, showColorTab=True),
701
+ _setter("yField", "数值字段", single=True, showDataLink=True),
702
+ _setter("ratio", "趋势值字段"),
703
+ _setter("totalValue", "总值字段"),
704
+ _setter("totalRatio", "总趋势值字段"),
705
+ ]}]
706
+ if chart_type == "funnel":
707
+ return [{"name": _DS_KEY_CHART, "title": "配置数据", "items": [
708
+ _setter("xField", "横轴", single=True, showFormatTab=True, showAggregateTab=False,
709
+ showDrillTab=True, showEditTab=True, showSortTab=True),
710
+ _setter("yField", "纵轴", showFormatTab=True, showEditTab=True, showSortTab=True, showDataLink=True),
711
+ ]}]
712
+ if chart_type == "combo":
713
+ return [{"name": _DS_KEY_DATASET, "title": "配置数据", "items": [
714
+ _setter("xField", "横轴", single=True),
715
+ _setter("leftYFields", "左纵轴", showDataLink=True),
716
+ _setter("rightYFields", "右纵轴", showDataLink=True),
717
+ _setter("annotationField", "参考线"),
718
+ ]}]
719
+ if chart_type == "table":
720
+ return [{"name": _DS_KEY_TABLE, "title": "配置数据", "items": [
721
+ _setter("columnFields", "列", showFormulaEditor=True, showFieldInfo=True,
722
+ showDataLink=True, supportDynamicAlias=True, showBatchSet=True,
723
+ batchSetFields=["text", "title", "aggregateType", "format_type", "format_decimalDigit"]),
724
+ ]}]
725
+ if chart_type == "indicator":
726
+ return [{"name": _DS_KEY_INDICATOR, "title": "指标数据", "items": [
727
+ _setter("kpi", "指标", single=False, showDataLink=True, supportDynamicAlias=True,
728
+ showBatchSet=True,
729
+ batchSetFields=["text", "title", "titleTip", "aggregateType",
730
+ "format_type", "format_decimalDigit", "unit"]),
731
+ _setter("helpKpi", "辅助指标", single=False, showDataLink=True),
732
+ ]}]
733
+ if chart_type == "pivot":
734
+ return [{"name": _DS_KEY_DATASET, "title": "配置数据", "items": [
735
+ _setter("columnList", "列", showFormatTab=True, showEditTab=True),
736
+ ]}]
737
+ if chart_type == "gauge":
738
+ return [{"name": _DS_KEY_CHART, "title": "配置数据", "items": [
739
+ _setter("valueField", "指标值", single=True),
740
+ _setter("assitValueField", "辅助值", single=True),
741
+ ]}]
742
+ return []
743
+
744
+
745
+ # ---------------------------------------------------------------------------
746
+ # mockData 构建(设计器预览数据)
747
+ # ---------------------------------------------------------------------------
748
+
749
+ def _build_mock_data(chart_type: str) -> list[dict[str, Any]]:
750
+ if chart_type == "bar":
751
+ return [{"name": _DS_KEY_CHART, "data": {"data": [
752
+ {"month": "Jan.", "value": 18.9}, {"month": "Feb.", "value": 28.8},
753
+ {"month": "Mar.", "value": 39.3}, {"month": "Apr.", "value": 81.4},
754
+ {"month": "May", "value": 47},
755
+ ], "meta": [
756
+ {"fieldKey": "xField", "dataType": "STRING", "title": "month"},
757
+ {"fieldKey": "yField", "dataType": "NUMBER", "title": "value"},
758
+ ], "currentPage": 1, "totalCount": 5}}]
759
+
760
+ if chart_type == "line":
761
+ return [{"name": _DS_KEY_CHART, "data": {"data": [
762
+ {"xField": "2020", "yField": 3}, {"xField": "2021", "yField": 4},
763
+ {"xField": "2022", "yField": 3.5}, {"xField": "2023", "yField": 5},
764
+ {"xField": "2024", "yField": 4.9},
765
+ ], "meta": [
766
+ {"fieldKey": "xField", "dataType": "STRING", "title": "xField"},
767
+ {"fieldKey": "yField", "dataType": "NUMBER", "title": "yField"},
768
+ ], "currentPage": 1, "totalCount": 5}}]
769
+
770
+ if chart_type == "pie":
771
+ return [{"name": _DS_KEY_CHART, "data": {"data": [
772
+ {"xField": "分类A", "yField": 63, "ratio": 0.8, "totalValue": 202, "totalRatio": 0.32},
773
+ {"xField": "分类B", "yField": 72, "ratio": 0.5, "totalValue": 202, "totalRatio": 0.36},
774
+ {"xField": "分类C", "yField": 67, "ratio": 0.3, "totalValue": 202, "totalRatio": 0.33},
775
+ ], "meta": [
776
+ {"fieldKey": "xField", "dataType": "STRING", "title": "xField"},
777
+ {"fieldKey": "yField", "dataType": "NUMBER", "title": "yField"},
778
+ {"fieldKey": "ratio", "dataType": "NUMBER", "title": "ratio"},
779
+ {"fieldKey": "totalValue", "dataType": "NUMBER", "title": "totalValue"},
780
+ {"fieldKey": "totalRatio", "dataType": "NUMBER", "title": "totalRatio"},
781
+ ], "currentPage": 1, "totalCount": 3}}]
782
+
783
+ if chart_type == "funnel":
784
+ return [{"name": _DS_KEY_CHART, "data": {"data": [
785
+ {"xField": "展示", "yField": 100}, {"xField": "点击", "yField": 80},
786
+ {"xField": "访问", "yField": 60}, {"xField": "咨询", "yField": 40},
787
+ {"xField": "订单", "yField": 20},
788
+ ], "meta": [
789
+ {"fieldKey": "xField", "dataType": "STRING", "title": "xField"},
790
+ {"fieldKey": "yField", "dataType": "NUMBER", "title": "yField"},
791
+ ], "currentPage": 1, "totalCount": 5}}]
792
+
793
+ if chart_type == "gauge":
794
+ return [{"name": _DS_KEY_CHART, "data": {"data": [
795
+ {"value": 75, "assitValue": 100},
796
+ ], "meta": [
797
+ {"fieldKey": "valueField", "dataType": "NUMBER", "title": "value"},
798
+ {"fieldKey": "assitValueField", "dataType": "NUMBER", "title": "assitValue"},
799
+ ], "currentPage": 1, "totalCount": 1}}]
800
+
801
+ if chart_type == "combo":
802
+ return [{"name": _DS_KEY_DATASET, "data": {"data": [
803
+ {"xField": "Jan.", "leftY": 18.9, "rightY": 5},
804
+ {"xField": "Feb.", "leftY": 28.8, "rightY": 8},
805
+ {"xField": "Mar.", "leftY": 39.3, "rightY": 12},
806
+ {"xField": "Apr.", "leftY": 81.4, "rightY": 15},
807
+ {"xField": "May", "leftY": 47, "rightY": 10},
808
+ ], "meta": [
809
+ {"fieldKey": "xField", "dataType": "STRING", "title": "xField"},
810
+ {"fieldKey": "leftYFields", "dataType": "NUMBER", "title": "leftY"},
811
+ {"fieldKey": "rightYFields", "dataType": "NUMBER", "title": "rightY"},
812
+ ], "currentPage": 1, "totalCount": 5}}]
813
+
814
+ if chart_type == "table":
815
+ return [{"name": _DS_KEY_TABLE, "data": {"data": [
816
+ {"col1": "数据1", "col2": "数据2", "col3": 100},
817
+ {"col1": "数据4", "col2": "数据5", "col3": 200},
818
+ {"col1": "数据7", "col2": "数据8", "col3": 300},
819
+ ], "meta": [
820
+ {"fieldKey": "columnFields", "dataType": "STRING", "title": "col1"},
821
+ {"fieldKey": "columnFields", "dataType": "STRING", "title": "col2"},
822
+ {"fieldKey": "columnFields", "dataType": "NUMBER", "title": "col3"},
823
+ ], "currentPage": 1, "totalCount": 3}}]
824
+
825
+ if chart_type == "indicator":
826
+ return [{"name": _DS_KEY_INDICATOR, "data": {"data": [
827
+ {"kpi1": 23123, "kpi2": 7712},
828
+ ], "meta": [
829
+ {"fieldKey": "kpi1", "dataType": "NUMBER", "title": "指标1", "category": "kpi"},
830
+ {"fieldKey": "kpi2", "dataType": "NUMBER", "title": "指标2", "category": "kpi"},
831
+ ], "currentPage": 1, "totalCount": 1}}]
832
+
833
+ if chart_type == "pivot":
834
+ return [{"name": _DS_KEY_DATASET, "data": {"data": [
835
+ {"col1": 74, "col2": 9, "col3": 79},
836
+ {"col1": 85, "col2": 15, "col3": 62},
837
+ {"col1": 93, "col2": 28, "col3": 44},
838
+ ], "meta": [
839
+ {"fieldKey": "columnList", "dataType": "NUMBER", "title": "col1"},
840
+ {"fieldKey": "columnList", "dataType": "NUMBER", "title": "col2"},
841
+ {"fieldKey": "columnList", "dataType": "NUMBER", "title": "col3"},
842
+ ], "currentPage": 1, "totalCount": 3}}]
843
+
844
+ return []
845
+
846
+
847
+ # ---------------------------------------------------------------------------
848
+ # afterFetch / exportData / link 构建
849
+ # ---------------------------------------------------------------------------
850
+
851
+ _AFTER_FETCH = {
852
+ "type": "JSFunction",
853
+ "value": "function afterFetch(data, extraInfo) { return data; }",
854
+ }
855
+
856
+ _EXPORT_DATA = {
857
+ "supportExport": False,
858
+ "passType": "NO_PASS",
859
+ "exportType": "BROWSER",
860
+ }
861
+
862
+ _LINK = {
863
+ "hasLink": False,
864
+ "content": {"type": "i18n", "zh_CN": "更多", "en_US": "More"},
865
+ "onlyIcon": True,
866
+ }
867
+
868
+
869
+ # ---------------------------------------------------------------------------
870
+ # 顶层字段属性提取
871
+ # ---------------------------------------------------------------------------
872
+
873
+ def _extract_top_level_field_props(chart_type: str, ds_model_map: dict[str, Any]) -> dict[str, Any]:
874
+ """从 dataSetModelMap 提取需要写入 props 顶层的字段属性。"""
875
+ result: dict[str, Any] = {}
876
+ if chart_type in ("bar", "line", "pie", "funnel"):
877
+ ds = ds_model_map.get(_DS_KEY_CHART, {})
878
+ result["xField"] = ds.get("xField", [])
879
+ result["yField"] = ds.get("yField", [])
880
+ if chart_type not in ("pie", "funnel"):
881
+ result["groupField"] = ds.get("groupField", [])
882
+ elif chart_type == "gauge":
883
+ ds = ds_model_map.get(_DS_KEY_CHART, {})
884
+ result["valueField"] = ds.get("valueField", [])
885
+ result["assitValueField"] = ds.get("assitValueField", [])
886
+ elif chart_type == "indicator":
887
+ ds = ds_model_map.get(_DS_KEY_INDICATOR, {})
888
+ result["kpiField"] = ds.get("kpi", [])
889
+ result["helpKpiField"] = ds.get("helpKpi", [])
890
+ elif chart_type == "table":
891
+ ds = ds_model_map.get(_DS_KEY_TABLE, {})
892
+ result["columnField"] = ds.get("columnFields", [])
893
+ elif chart_type == "combo":
894
+ ds = ds_model_map.get(_DS_KEY_DATASET, {})
895
+ result["xField"] = ds.get("xField", [])
896
+ result["leftYFields"] = ds.get("leftYFields", [])
897
+ result["rightYFields"] = ds.get("rightYFields", [])
898
+ elif chart_type == "pivot":
899
+ ds = ds_model_map.get(_DS_KEY_DATASET, {})
900
+ result["columnList"] = ds.get("columnList", [])
901
+ return result
902
+
903
+
904
+ # ---------------------------------------------------------------------------
905
+ # 主入口
906
+ # ---------------------------------------------------------------------------
907
+
908
+
909
+ def build_chart_component(
910
+ chart: dict[str, Any],
911
+ cube_tenant_id: str = "",
912
+ ) -> tuple[dict[str, Any], str, dict[str, Any]]:
913
+ """
914
+ 构造图表组件。
915
+
916
+ Returns:
917
+ (component_node, fieldId, default_layout)
918
+ """
919
+ chart_type = chart.get("type", "bar")
920
+ if chart_type not in CHART_TYPE_MAP:
921
+ raise ValueError(f"不支持的图表类型: {chart_type}(支持: {list(CHART_TYPE_MAP.keys())})")
922
+
923
+ component_name = CHART_TYPE_MAP[chart_type]
924
+ title = chart.get("title", "图表")
925
+ field_id = generate_field_id(component_name)
926
+ node_id = next_node_id()
927
+
928
+ cube_code = normalize_cube_code(chart.get("cubeCode", ""))
929
+ if not cube_code:
930
+ raise ValueError(f"图表 '{title}' 缺少 cubeCode")
931
+
932
+ data_set_model_map = _build_data_set_model_map(chart, cube_code, cube_tenant_id)
933
+
934
+ props: dict[str, Any] = {
935
+ "fieldId": field_id,
936
+ "cid": node_id,
937
+ "showComponentTitle": True,
938
+ "componentTitle": i18n(title),
939
+ "componentTitleTextAlign": "LEFT",
940
+ "titleTipContent": i18n(""),
941
+ "titleTipIconName": "help",
942
+ "headerSize": "medium",
943
+ "link": _LINK,
944
+ "exportData": _EXPORT_DATA,
945
+ "openRefresh": True,
946
+ "enabledCache": True,
947
+ "auth": [],
948
+ "afterFetch": _AFTER_FETCH,
949
+ "__style__": {},
950
+ "mockData": _build_mock_data(chart_type),
951
+ "dataSetModelMap": data_set_model_map,
952
+ "userConfig": _build_user_config(chart_type),
953
+ "settings": _get_chart_settings(chart_type, chart),
954
+ "titleTip": False,
955
+ "hasFullscreen": False,
956
+ "copyAsImg": False,
957
+ "height": None,
958
+ "isHeightAuto": True,
959
+ "datasetModel": {"filterList": []},
960
+ }
961
+
962
+ top_level = _extract_top_level_field_props(chart_type, data_set_model_map)
963
+ props.update(top_level)
964
+
965
+ if chart_type in ("table", "indicator"):
966
+ props["showFieldSelectIcon"] = True
967
+
968
+ if chart_type == "table":
969
+ props["pageSize"] = chart.get("pageSize", 20)
970
+
971
+ node: dict[str, Any] = {
972
+ "componentName": component_name,
973
+ "id": node_id,
974
+ "props": props,
975
+ }
976
+
977
+ computed = _compute_dynamic_layout(chart_type, chart)
978
+ layout: dict[str, Any] = {
979
+ "w": chart.get("w", computed["w"]),
980
+ "h": chart.get("h", computed["h"]),
981
+ }
982
+ for k in ("minH", "maxH", "resizeHandles"):
983
+ if k in computed:
984
+ layout[k] = computed[k]
985
+
986
+ return node, field_id, layout
987
+
988
+
989
+ # ---------------------------------------------------------------------------
990
+ # dataSetModelMap 构造
991
+ # ---------------------------------------------------------------------------
992
+
993
+
994
+ def _build_data_set_model_map(
995
+ chart: dict[str, Any],
996
+ cube_code: str,
997
+ cube_tenant_id: str,
998
+ ) -> dict[str, Any]:
999
+ chart_type = chart.get("type", "bar")
1000
+
1001
+ if chart_type in ("bar", "line", "pie", "funnel"):
1002
+ return _build_xy_data_model(chart, cube_code, cube_tenant_id)
1003
+ elif chart_type == "table":
1004
+ return _build_table_data_model(chart, cube_code, cube_tenant_id)
1005
+ elif chart_type == "indicator":
1006
+ return _build_indicator_data_model(chart, cube_code, cube_tenant_id)
1007
+ elif chart_type == "gauge":
1008
+ return _build_gauge_data_model(chart, cube_code, cube_tenant_id)
1009
+ elif chart_type == "combo":
1010
+ return _build_combo_data_model(chart, cube_code, cube_tenant_id)
1011
+ elif chart_type == "pivot":
1012
+ return _build_pivot_data_model(chart, cube_code, cube_tenant_id)
1013
+ return {}
1014
+
1015
+
1016
+ def _build_xy_data_model(
1017
+ chart: dict[str, Any],
1018
+ cube_code: str,
1019
+ cube_tenant_id: str,
1020
+ ) -> dict[str, Any]:
1021
+ chart_type = chart.get("type", "bar")
1022
+ x_raw = chart.get("xField", "")
1023
+ x_resolved = _resolve_field(x_raw, cube_code)
1024
+
1025
+ y_raw = chart.get("yField", "")
1026
+ if isinstance(y_raw, (str, dict)):
1027
+ y_raw = [y_raw]
1028
+ y_resolved_list = [_resolve_field(f, cube_code) for f in y_raw]
1029
+
1030
+ agg_type = chart.get("aggregateType", "COUNT").upper()
1031
+
1032
+ x_label = _apply_cube_label_suffix(
1033
+ x_resolved["fieldCode"], chart.get("xLabel", "") or x_resolved["text"]
1034
+ )
1035
+ y_labels_raw = chart.get("yLabel", [])
1036
+ if isinstance(y_labels_raw, str):
1037
+ y_labels_raw = [y_labels_raw]
1038
+
1039
+ x_alias = _gen_alias()
1040
+ x_time_gran = x_resolved["timeGranularityType"] or (
1041
+ chart.get("timeGranularityType", "DAY") if _is_date_field(x_resolved["fieldCode"]) else None
1042
+ )
1043
+
1044
+ query_defs = [_build_query_field_def(
1045
+ x_alias, x_label, cube_code, x_resolved["fieldCode"], x_resolved["dataType"],
1046
+ "NONE", x_time_gran, classified_code=x_resolved["classifiedCode"],
1047
+ )]
1048
+ x_full = _build_full_field(
1049
+ x_alias, x_label, cube_code, x_resolved["fieldCode"], x_resolved["dataType"],
1050
+ "NONE", x_time_gran, classified_code=x_resolved["classifiedCode"],
1051
+ field_id=x_resolved["id"], time_format=x_resolved["timeFormat"],
1052
+ )
1053
+ all_full = [x_full]
1054
+
1055
+ y_aliases: list[str] = []
1056
+ y_fulls: list[dict[str, Any]] = []
1057
+ for i, yr in enumerate(y_resolved_list):
1058
+ y_label = _apply_cube_label_suffix(
1059
+ yr["fieldCode"], (y_labels_raw[i] if i < len(y_labels_raw) else "") or yr["text"]
1060
+ )
1061
+ y_alias = _gen_alias()
1062
+ y_aliases.append(y_alias)
1063
+ y_fc, y_dt = _fix_array_field_for_aggregate(yr["fieldCode"], yr["dataType"], agg_type)
1064
+ query_defs.append(_build_query_field_def(
1065
+ y_alias, y_label, cube_code, y_fc, y_dt,
1066
+ agg_type, classified_code=yr["classifiedCode"],
1067
+ ))
1068
+ y_full = _build_full_field(
1069
+ y_alias, y_label, cube_code, y_fc, y_dt,
1070
+ agg_type, classified_code=yr["classifiedCode"], field_id=yr["id"],
1071
+ )
1072
+ y_fulls.append(y_full)
1073
+ all_full.append(y_full)
1074
+
1075
+ extra: dict[str, Any] = {"xField": [x_full], "yField": y_fulls}
1076
+ if chart_type == "pie":
1077
+ extra.update({"ratio": [], "totalValue": [], "totalRatio": [], "trailingIconField": []})
1078
+ elif chart_type != "funnel":
1079
+ extra.update({"groupField": [], "annotationField": []})
1080
+
1081
+ limit_val = chart.get("limit")
1082
+ if limit_val is not None:
1083
+ extra["limit"] = int(limit_val)
1084
+
1085
+ return _wrap_dataset(
1086
+ _DS_KEY_CHART, cube_code, cube_tenant_id,
1087
+ query_defs, [x_alias] + y_aliases, all_full,
1088
+ extra=extra,
1089
+ )
1090
+
1091
+
1092
+ def _build_table_data_model(
1093
+ chart: dict[str, Any],
1094
+ cube_code: str,
1095
+ cube_tenant_id: str,
1096
+ ) -> dict[str, Any]:
1097
+ raw_columns = chart.get("columnFields", []) or chart.get("columns", []) or chart.get("fields", [])
1098
+ if not raw_columns:
1099
+ x_field = chart.get("xField", "")
1100
+ if x_field:
1101
+ raw_columns = [x_field]
1102
+ if not raw_columns:
1103
+ raise ValueError(
1104
+ "table 图表必须提供 columnFields(或 columns / fields / xField)。"
1105
+ "请先通过 `dws yida form components` 获取源表字段定义。"
1106
+ )
1107
+
1108
+ column_labels_raw = chart.get("columnLabels", [])
1109
+ resolved_columns = [_resolve_field(col, cube_code) for col in raw_columns]
1110
+
1111
+ query_defs: list[dict[str, Any]] = []
1112
+ aliases: list[str] = []
1113
+ full_fields: list[dict[str, Any]] = []
1114
+
1115
+ for i, rc in enumerate(resolved_columns):
1116
+ label = _apply_cube_label_suffix(
1117
+ rc["fieldCode"], (column_labels_raw[i] if i < len(column_labels_raw) else "") or rc["text"]
1118
+ )
1119
+ alias = _gen_alias()
1120
+ aliases.append(alias)
1121
+ time_gran = rc["timeGranularityType"] or (
1122
+ chart.get("timeGranularityType", "DAY") if _is_date_field(rc["fieldCode"]) else None
1123
+ )
1124
+ query_defs.append(_build_query_field_def(
1125
+ alias, label, cube_code, rc["fieldCode"], rc["dataType"],
1126
+ "NONE", time_gran, classified_code=rc["classifiedCode"],
1127
+ ))
1128
+ full = _build_full_field(
1129
+ alias, label, cube_code, rc["fieldCode"], rc["dataType"],
1130
+ "NONE", time_gran, classified_code=rc["classifiedCode"],
1131
+ field_id=rc["id"], time_format=rc["timeFormat"],
1132
+ )
1133
+ full["sortable"] = False
1134
+ full["hidden"] = False
1135
+ full_fields.append(full)
1136
+
1137
+ column_fields: list[dict[str, Any]] = []
1138
+ for i, full in enumerate(full_fields):
1139
+ col: dict[str, Any] = {
1140
+ "aggregateType": full["aggregateType"],
1141
+ "beUsedTimes": 1,
1142
+ "classifiedCode": full["classifiedCode"],
1143
+ "cubeCode": full["cubeCode"],
1144
+ "dataType": full["dataType"],
1145
+ "fieldCode": full["fieldCode"],
1146
+ "fieldKey": full["fieldKey"],
1147
+ "id": full["id"],
1148
+ "text": full["text"],
1149
+ "title": full["title"],
1150
+ "visible": True,
1151
+ "width": 120,
1152
+ "align": "left",
1153
+ "fixed": "left" if i == 0 else None,
1154
+ "timeGranularityType": full.get("timeGranularityType"),
1155
+ "timeFormat": full.get("timeFormat"),
1156
+ "orderBy": full["orderBy"],
1157
+ }
1158
+ column_fields.append(col)
1159
+
1160
+ return _wrap_dataset(
1161
+ _DS_KEY_TABLE, cube_code, cube_tenant_id,
1162
+ query_defs, aliases, full_fields,
1163
+ extra={"columnFields": column_fields},
1164
+ )
1165
+
1166
+
1167
+ def _build_indicator_data_model(
1168
+ chart: dict[str, Any],
1169
+ cube_code: str,
1170
+ cube_tenant_id: str,
1171
+ ) -> dict[str, Any]:
1172
+ kpi_list = chart.get("kpi", []) or chart.get("kpiField", []) or chart.get("yField", []) or chart.get("fields", [])
1173
+ if not kpi_list:
1174
+ raise ValueError("indicator 图表必须提供 kpi(或 kpiField / yField / fields)数组")
1175
+
1176
+ query_defs: list[dict[str, Any]] = []
1177
+ aliases: list[str] = []
1178
+ full_fields: list[dict[str, Any]] = []
1179
+
1180
+ kpi_rich: list[dict[str, Any]] = []
1181
+ for kpi in kpi_list:
1182
+ if isinstance(kpi, str):
1183
+ kpi = {"fieldCode": kpi}
1184
+ fc = normalize_field_code(kpi.get("fieldCode", ""))
1185
+ agg = kpi.get("aggregateType", "COUNT").upper()
1186
+ dt = kpi.get("dataType") or _infer_data_type(fc)
1187
+ fc, dt = _fix_array_field_for_aggregate(fc, dt, agg)
1188
+ label = kpi.get("aliasName", "") or kpi.get("text", "") or kpi.get("label", "") or _derive_label(fc)
1189
+ label = _apply_cube_label_suffix(fc, label)
1190
+ field_id = kpi.get("id") or fc
1191
+ classified_code = kpi.get("classifiedCode") or cube_code
1192
+ alias = _gen_alias()
1193
+ aliases.append(alias)
1194
+ query_defs.append(_build_query_field_def(
1195
+ alias, label, cube_code, fc, dt, agg, classified_code=classified_code,
1196
+ ))
1197
+ full = _build_full_field(
1198
+ alias, label, cube_code, fc, dt, agg,
1199
+ classified_code=classified_code, field_id=field_id,
1200
+ )
1201
+ full_fields.append(full)
1202
+ kpi_item: dict[str, Any] = {
1203
+ **full,
1204
+ "visible": True,
1205
+ "isVisible": "y",
1206
+ }
1207
+ kpi_rich.append(kpi_item)
1208
+
1209
+ help_kpi_list = chart.get("helpKpi", [])
1210
+ help_kpi_rich: list[dict[str, Any]] = []
1211
+ for hk in help_kpi_list:
1212
+ if isinstance(hk, str):
1213
+ hk = {"fieldCode": hk}
1214
+ fc = normalize_field_code(hk.get("fieldCode", ""))
1215
+ agg = hk.get("aggregateType", "COUNT").upper()
1216
+ dt = hk.get("dataType") or _infer_data_type(fc)
1217
+ fc, dt = _fix_array_field_for_aggregate(fc, dt, agg)
1218
+ label = hk.get("aliasName", "") or hk.get("text", "") or hk.get("label", "") or _derive_label(fc)
1219
+ label = _apply_cube_label_suffix(fc, label)
1220
+ field_id = hk.get("id") or fc
1221
+ classified_code = hk.get("classifiedCode") or cube_code
1222
+ alias = _gen_alias()
1223
+ aliases.append(alias)
1224
+ query_defs.append(_build_query_field_def(
1225
+ alias, label, cube_code, fc, dt, agg, classified_code=classified_code,
1226
+ ))
1227
+ full = _build_full_field(
1228
+ alias, label, cube_code, fc, dt, agg,
1229
+ classified_code=classified_code, field_id=field_id,
1230
+ )
1231
+ full_fields.append(full)
1232
+ help_kpi_rich.append({**full, "visible": True, "isVisible": "y"})
1233
+
1234
+ return _wrap_dataset(
1235
+ _DS_KEY_INDICATOR, cube_code, cube_tenant_id,
1236
+ query_defs, aliases, full_fields,
1237
+ extra={"kpi": kpi_rich, "helpKpi": help_kpi_rich},
1238
+ )
1239
+
1240
+
1241
+ def _build_gauge_data_model(
1242
+ chart: dict[str, Any],
1243
+ cube_code: str,
1244
+ cube_tenant_id: str,
1245
+ ) -> dict[str, Any]:
1246
+ value_raw = chart.get("valueField") or chart.get("yField")
1247
+ if isinstance(value_raw, list):
1248
+ value_raw = value_raw[0] if value_raw else None
1249
+ if not value_raw:
1250
+ raise ValueError("gauge 图表必须提供 valueField(或 yField)")
1251
+
1252
+ value_resolved = _resolve_field(value_raw, cube_code)
1253
+ agg_type = chart.get("aggregateType", "AVG").upper()
1254
+
1255
+ v_alias = _gen_alias()
1256
+ v_label = _apply_cube_label_suffix(
1257
+ value_resolved["fieldCode"], chart.get("valueLabel", "") or value_resolved["text"]
1258
+ )
1259
+ v_fc, v_dt = _fix_array_field_for_aggregate(value_resolved["fieldCode"], value_resolved["dataType"], agg_type)
1260
+
1261
+ query_defs = [_build_query_field_def(
1262
+ v_alias, v_label, cube_code, v_fc, v_dt, agg_type,
1263
+ classified_code=value_resolved["classifiedCode"],
1264
+ )]
1265
+ v_full = _build_full_field(
1266
+ v_alias, v_label, cube_code, v_fc, v_dt, agg_type,
1267
+ classified_code=value_resolved["classifiedCode"], field_id=value_resolved["id"],
1268
+ )
1269
+ all_full = [v_full]
1270
+ aliases = [v_alias]
1271
+
1272
+ assit_fulls: list[dict[str, Any]] = []
1273
+ assit_raw = chart.get("assitValueField")
1274
+ if assit_raw:
1275
+ if isinstance(assit_raw, list):
1276
+ assit_raw = assit_raw[0] if assit_raw else None
1277
+ if assit_raw:
1278
+ assit_resolved = _resolve_field(assit_raw, cube_code)
1279
+ a_alias = _gen_alias()
1280
+ a_label = _apply_cube_label_suffix(
1281
+ assit_resolved["fieldCode"], chart.get("assitLabel", "") or assit_resolved["text"]
1282
+ )
1283
+ a_fc, a_dt = _fix_array_field_for_aggregate(
1284
+ assit_resolved["fieldCode"], assit_resolved["dataType"], agg_type
1285
+ )
1286
+ query_defs.append(_build_query_field_def(
1287
+ a_alias, a_label, cube_code, a_fc, a_dt, agg_type,
1288
+ classified_code=assit_resolved["classifiedCode"],
1289
+ ))
1290
+ a_full = _build_full_field(
1291
+ a_alias, a_label, cube_code, a_fc, a_dt, agg_type,
1292
+ classified_code=assit_resolved["classifiedCode"], field_id=assit_resolved["id"],
1293
+ )
1294
+ all_full.append(a_full)
1295
+ aliases.append(a_alias)
1296
+ assit_fulls.append(a_full)
1297
+
1298
+ return _wrap_dataset(
1299
+ _DS_KEY_CHART, cube_code, cube_tenant_id,
1300
+ query_defs, aliases, all_full,
1301
+ extra={"valueField": [v_full], "assitValueField": assit_fulls},
1302
+ )
1303
+
1304
+
1305
+ def _build_combo_data_model(
1306
+ chart: dict[str, Any],
1307
+ cube_code: str,
1308
+ cube_tenant_id: str,
1309
+ ) -> dict[str, Any]:
1310
+ x_raw = chart.get("xField", "")
1311
+ x_resolved = _resolve_field(x_raw, cube_code)
1312
+
1313
+ left_raw = chart.get("leftYFields", [])
1314
+ if isinstance(left_raw, (str, dict)):
1315
+ left_raw = [left_raw]
1316
+ right_raw = chart.get("rightYFields", [])
1317
+ if isinstance(right_raw, (str, dict)):
1318
+ right_raw = [right_raw]
1319
+
1320
+ if not left_raw and not right_raw:
1321
+ raise ValueError("combo 图表必须提供 leftYFields 或 rightYFields")
1322
+
1323
+ left_resolved = [_resolve_field(f, cube_code) for f in left_raw]
1324
+ right_resolved = [_resolve_field(f, cube_code) for f in right_raw]
1325
+
1326
+ left_agg = chart.get("leftAggregateType", "SUM").upper()
1327
+ right_agg = chart.get("rightAggregateType", "SUM").upper()
1328
+
1329
+ x_label = _apply_cube_label_suffix(
1330
+ x_resolved["fieldCode"], chart.get("xLabel", "") or x_resolved["text"]
1331
+ )
1332
+ x_alias = _gen_alias()
1333
+ x_time_gran = x_resolved["timeGranularityType"] or (
1334
+ chart.get("timeGranularityType", "DAY") if _is_date_field(x_resolved["fieldCode"]) else None
1335
+ )
1336
+
1337
+ query_defs = [_build_query_field_def(
1338
+ x_alias, x_label, cube_code, x_resolved["fieldCode"], x_resolved["dataType"],
1339
+ "NONE", x_time_gran, classified_code=x_resolved["classifiedCode"],
1340
+ )]
1341
+ x_full = _build_full_field(
1342
+ x_alias, x_label, cube_code, x_resolved["fieldCode"], x_resolved["dataType"],
1343
+ "NONE", x_time_gran, classified_code=x_resolved["classifiedCode"],
1344
+ field_id=x_resolved["id"], time_format=x_resolved["timeFormat"],
1345
+ )
1346
+ all_full = [x_full]
1347
+ all_aliases = [x_alias]
1348
+
1349
+ left_fulls: list[dict[str, Any]] = []
1350
+ for lr in left_resolved:
1351
+ alias = _gen_alias()
1352
+ all_aliases.append(alias)
1353
+ label = _apply_cube_label_suffix(lr["fieldCode"], lr["text"])
1354
+ fc, dt = _fix_array_field_for_aggregate(lr["fieldCode"], lr["dataType"], left_agg)
1355
+ query_defs.append(_build_query_field_def(
1356
+ alias, label, cube_code, fc, dt, left_agg, classified_code=lr["classifiedCode"],
1357
+ ))
1358
+ full = _build_full_field(
1359
+ alias, label, cube_code, fc, dt, left_agg,
1360
+ classified_code=lr["classifiedCode"], field_id=lr["id"],
1361
+ )
1362
+ left_fulls.append(full)
1363
+ all_full.append(full)
1364
+
1365
+ right_fulls: list[dict[str, Any]] = []
1366
+ for rr in right_resolved:
1367
+ alias = _gen_alias()
1368
+ all_aliases.append(alias)
1369
+ label = _apply_cube_label_suffix(rr["fieldCode"], rr["text"])
1370
+ fc, dt = _fix_array_field_for_aggregate(rr["fieldCode"], rr["dataType"], right_agg)
1371
+ query_defs.append(_build_query_field_def(
1372
+ alias, label, cube_code, fc, dt, right_agg, classified_code=rr["classifiedCode"],
1373
+ ))
1374
+ full = _build_full_field(
1375
+ alias, label, cube_code, fc, dt, right_agg,
1376
+ classified_code=rr["classifiedCode"], field_id=rr["id"],
1377
+ )
1378
+ right_fulls.append(full)
1379
+ all_full.append(full)
1380
+
1381
+ return _wrap_dataset(
1382
+ _DS_KEY_DATASET, cube_code, cube_tenant_id,
1383
+ query_defs, all_aliases, all_full,
1384
+ extra={
1385
+ "xField": [x_full],
1386
+ "leftYFields": left_fulls,
1387
+ "rightYFields": right_fulls,
1388
+ "annotationField": [],
1389
+ },
1390
+ )
1391
+
1392
+
1393
+ def _build_pivot_data_model(
1394
+ chart: dict[str, Any],
1395
+ cube_code: str,
1396
+ cube_tenant_id: str,
1397
+ ) -> dict[str, Any]:
1398
+ raw_columns = chart.get("columnList", []) or chart.get("columns", [])
1399
+ if not raw_columns:
1400
+ raise ValueError(
1401
+ "pivot 图表必须提供 columnList(或 columns)。"
1402
+ "请先通过 `dws yida form components` 获取源表字段定义。"
1403
+ )
1404
+
1405
+ resolved_columns = [_resolve_field(col, cube_code) for col in raw_columns]
1406
+
1407
+ query_defs: list[dict[str, Any]] = []
1408
+ aliases: list[str] = []
1409
+ full_fields: list[dict[str, Any]] = []
1410
+
1411
+ for rc in resolved_columns:
1412
+ label = _apply_cube_label_suffix(rc["fieldCode"], rc["text"])
1413
+ alias = _gen_alias()
1414
+ aliases.append(alias)
1415
+ time_gran = rc["timeGranularityType"] or (
1416
+ chart.get("timeGranularityType", "DAY") if _is_date_field(rc["fieldCode"]) else None
1417
+ )
1418
+ query_defs.append(_build_query_field_def(
1419
+ alias, label, cube_code, rc["fieldCode"], rc["dataType"],
1420
+ "NONE", time_gran, classified_code=rc["classifiedCode"],
1421
+ ))
1422
+ full = _build_full_field(
1423
+ alias, label, cube_code, rc["fieldCode"], rc["dataType"],
1424
+ "NONE", time_gran, classified_code=rc["classifiedCode"],
1425
+ field_id=rc["id"], time_format=rc["timeFormat"],
1426
+ )
1427
+ full_fields.append(full)
1428
+
1429
+ return _wrap_dataset(
1430
+ _DS_KEY_DATASET, cube_code, cube_tenant_id,
1431
+ query_defs, aliases, full_fields,
1432
+ extra={"columnList": full_fields},
1433
+ extra_query={"filterMode": "PROFESSIONAL"},
1434
+ )