openyida 2026.9.21 → 2026.9.22-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -20
- package/bin/yida.js +6 -11
- package/lib/app/app-list.js +3 -7
- package/lib/app/canvas-compile.js +12 -22
- package/lib/app/check-prd-completeness.js +0 -7
- package/lib/app/create-app.js +1 -4
- package/lib/app/create-form/args.js +12 -37
- package/lib/app/create-form/batch.js +11 -86
- package/lib/app/create-form.js +86 -193
- package/lib/app/create-page.js +17 -84
- package/lib/app/custom-theme.js +0 -11
- package/lib/app/form-field-validator.js +41 -26
- package/lib/app/form-open-guard.js +10 -97
- package/lib/app/get-form-config.js +0 -1
- package/lib/app/inline-css-guard.js +31 -1
- package/lib/app/services/form-compiler.js +4 -2
- package/lib/app/theme-from-design.js +41 -144
- package/lib/app/theme-presets.js +1 -1
- package/lib/app/update-app.js +13 -63
- package/lib/asset/ai-image.js +9 -59
- package/lib/asset/asset-cmd.js +7 -18
- package/lib/asset/asset-plan.js +9 -102
- package/lib/asset/asset-resolve.js +10 -55
- package/lib/asset/asset-status.js +4 -5
- package/lib/asset/host-capabilities.js +2 -11
- package/lib/asset/url-verify.js +4 -19
- package/lib/auth/dws-sync.js +148 -0
- package/lib/auth/token-auth.js +73 -9
- package/lib/auth/token-store.js +50 -0
- package/lib/connector/connector-test.js +5 -19
- package/lib/connector/contract.js +1 -3
- package/lib/core/agent-capabilities.js +16 -19
- package/lib/core/command-manifest.js +40 -329
- package/lib/core/locales/en.js +17 -74
- package/lib/core/locales/zh.js +16 -73
- package/lib/core/redact.js +10 -15
- package/lib/core/sample.js +30 -72
- package/lib/core/utils.js +4 -0
- package/lib/design-plan/design-plan.js +4 -51
- package/lib/design-plan/init.js +26 -121
- package/lib/design-plan/materialize.js +348 -451
- package/lib/design-plan/normalize.js +29 -74
- package/lib/design-plan/parallel.js +16 -71
- package/lib/design-plan/patch.js +16 -63
- package/lib/design-plan/preview.js +8 -6
- package/lib/design-plan/validate.js +11 -71
- package/lib/process/create-process.js +50 -84
- package/lib/samples/openyida-scaffold/canvas-form-drawer.canvas.jsx +90 -20
- package/lib/samples/openyida-scaffold/canvas-nav/content.jsx +13 -93
- package/lib/samples/openyida-scaffold/canvas-nav/data.jsx +18 -100
- package/lib/samples/openyida-scaffold/canvas-nav/mixed.jsx +4 -6
- package/lib/samples/openyida-scaffold/canvas-nav/shared.jsx +5 -5
- package/lib/samples/openyida-scaffold/canvas-nav/side.jsx +2 -1
- package/lib/samples/openyida-scaffold/canvas-nav/sidebar.jsx +1 -1
- package/lib/samples/openyida-scaffold/canvas-nav/top.jsx +9 -15
- package/lib/samples/yida-canvas-table-form/table-form-batch-submit.canvas.jsx +83 -9
- package/lib/samples/yida-rechart/trend-combo.canvas.jsx +87 -14
- package/package.json +1 -3
- package/scripts/postinstall.js +3 -3
- package/yida-skills/SKILL.md +16 -19
- package/yida-skills/references/official-example-schema-patterns.md +1 -1
- package/yida-skills/references/yida-api.md +0 -4
- package/yida-skills/skills/yida-app/SKILL.md +23 -46
- package/yida-skills/skills/yida-app/workflow/parallel-work.md +6 -15
- package/yida-skills/skills/yida-app/workflow/plan/step-1-understand.md +1 -1
- package/yida-skills/skills/yida-app/workflow/plan/step-2-confirm.md +1 -1
- package/yida-skills/skills/yida-app/workflow/plan/step-4-deliver.md +15 -29
- package/yida-skills/skills/yida-app/workflow/plan/workflow.md +11 -29
- package/yida-skills/skills/yida-app/workflow/step-1-resource-context.md +2 -4
- package/yida-skills/skills/yida-app/workflow/step-2-design.md +9 -23
- package/yida-skills/skills/yida-app/workflow/step-3-create-or-reuse-app.md +4 -6
- package/yida-skills/skills/yida-app/workflow/step-4-forms-processes.md +4 -15
- package/yida-skills/skills/yida-app/workflow/step-6-main-page.md +4 -6
- package/yida-skills/skills/yida-app/workflow/step-7-page-code.md +9 -15
- package/yida-skills/skills/yida-app/workflow/step-8-publish-navigation.md +11 -25
- package/yida-skills/skills/yida-app/workflow/step-9-output-finish.md +28 -68
- package/yida-skills/skills/yida-canvas-custom-page/SKILL.md +43 -42
- package/yida-skills/skills/yida-canvas-custom-page/references/canvas-style-implementation-guide.md +44 -60
- package/yida-skills/skills/yida-canvas-custom-page/references/canvas-theme-provider.md +50 -72
- package/yida-skills/skills/yida-canvas-custom-page/references/component-library-guide.md +1 -13
- package/yida-skills/skills/yida-canvas-custom-page/references/data-bridge-guide.md +1 -140
- package/yida-skills/skills/yida-canvas-custom-page/references/navigation-and-entry-guide.md +72 -101
- package/yida-skills/skills/yida-canvas-custom-page/references/page-generation-guide.md +32 -35
- package/yida-skills/skills/yida-canvas-custom-page/scripts/build-canvas-theme.js +3 -29
- package/yida-skills/skills/yida-canvas-custom-page/scripts/canvas-theme-provider.template.jsx +6 -69
- package/yida-skills/skills/yida-canvas-data-binding/SKILL.md +0 -26
- package/yida-skills/skills/yida-create-app/SKILL.md +0 -2
- package/yida-skills/skills/yida-create-form-page/SKILL.md +58 -72
- package/yida-skills/skills/yida-create-form-page/references/advanced-form-modes.md +5 -5
- package/yida-skills/skills/yida-create-form-page/references/association-form-field.md +4 -4
- package/yida-skills/skills/yida-create-form-page/references/batch-forms.md +5 -6
- package/yida-skills/skills/yida-create-form-page/references/field-definition-guide.md +19 -7
- package/yida-skills/skills/yida-create-form-page/references/form-field-properties.md +44 -62
- package/yida-skills/skills/yida-create-page/SKILL.md +6 -14
- package/yida-skills/skills/yida-create-process/SKILL.md +2 -13
- package/yida-skills/skills/yida-custom-page/SKILL.md +0 -2
- package/yida-skills/skills/yida-custom-page/references/design-system.md +1 -1
- package/yida-skills/skills/yida-dashboard/SKILL.md +4 -5
- package/yida-skills/skills/yida-data-management/SKILL.md +2 -4
- package/yida-skills/skills/yida-data-management/references/data-format-guide.md +4 -4
- package/yida-skills/skills/yida-design/SKILL.md +14 -29
- package/yida-skills/skills/yida-design/references/app/blueprint.md +70 -0
- package/yida-skills/skills/yida-design/references/app/navigation-patterns.md +43 -0
- package/yida-skills/skills/yida-design/references/app/role-journey.md +30 -0
- package/yida-skills/skills/yida-design/references/ask-human-interaction-contract.md +42 -67
- package/yida-skills/skills/yida-design/references/asset-workflow.md +2 -6
- package/yida-skills/skills/yida-design/references/design-mode.md +4 -4
- package/yida-skills/skills/yida-design/references/page-quality-gates.md +38 -26
- package/yida-skills/skills/yida-design/references/style-design-selection.md +137 -0
- package/yida-skills/skills/yida-design/references/style-designs/_design-md-template.md +185 -0
- package/yida-skills/skills/yida-design/references/style-designs/aqua-service-progress-dashboard.md +242 -0
- package/yida-skills/skills/yida-design/references/style-designs/blue-insight-operations-dashboard.md +243 -0
- package/yida-skills/skills/yida-design/references/style-designs/blue-productivity-insight-workbench.md +242 -0
- package/yida-skills/skills/yida-design/references/style-designs/command-filter-card-console.md +304 -0
- package/yida-skills/skills/yida-design/references/style-designs/contrast-command-analytics-workbench.md +261 -0
- package/yida-skills/skills/yida-design/references/style-designs/dark-stage-analytic-dashboard.md +369 -0
- package/yida-skills/skills/yida-design/references/style-designs/filterable-card-catalog.md +354 -0
- package/yida-skills/skills/yida-design/references/style-designs/green-timeline-progress-workbench.md +250 -0
- package/yida-skills/skills/yida-design/references/style-designs/registry.md +117 -0
- package/yida-skills/skills/yida-design/references/style-designs/soft-analytic-workbench.md +348 -0
- package/yida-skills/skills/yida-design/references/style-designs/soft-blue-grid-analytic-dashboard.md +658 -0
- package/yida-skills/skills/yida-design/references/style-designs/soft-bordered-analytic-workbench.md +385 -0
- package/yida-skills/skills/yida-design/references/style-designs/soft-curated-filter-gallery.md +300 -0
- package/yida-skills/skills/yida-design/references/style-designs/soft-modular-analytic-workbench.md +404 -0
- package/yida-skills/skills/yida-design/references/style-designs/soft-progress-analytics-workbench.md +382 -0
- package/yida-skills/skills/yida-design/references/style-designs/soft-timeline-analytics-workbench.md +367 -0
- package/yida-skills/skills/yida-design/references/style-designs/teal-rail-analytics-workbench.md +341 -0
- package/yida-skills/skills/yida-design/references/theme/app-custom-theme-template.css +432 -350
- package/yida-skills/skills/yida-design/references/visual-decision-engine.md +143 -19
- package/yida-skills/skills/yida-design/references/visual-scaffold-recipes.md +27 -15
- package/yida-skills/skills/yida-design/sub_skill/page-design/SKILL.md +0 -4
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/SKILL.md +8 -22
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/assets/README.md +10 -14
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/assets/build-plan-template.html +4 -9
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/build-plan-compact-schema.md +27 -49
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/build-plan-schema.md +154 -33
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/visual-design.md +127 -48
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/visual-theme-selection.md +51 -37
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/scripts/render_build_plan.py +48 -43
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/scripts/validate_design_themes.py +190 -0
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/README.md +98 -0
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/airy-media-grid.md +339 -0
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/airy-modular-clarity.md +348 -0
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/airy-structured-clarity.md +344 -0
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/ambient-halo-layered.md +345 -0
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/dark-focus-layered.md +355 -0
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/dark-luminous-modular.md +377 -0
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/deep-stage-duotone.md +352 -0
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/hairline-runway-clarity.md +389 -0
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/high-contrast-modular.md +364 -0
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/index.json +329 -0
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/interlocked-vivid-modules.md +348 -0
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/matrix-grid-focus.md +345 -0
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/media-rail-inspector.md +379 -0
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/mist-layered-signal.md +347 -0
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/modular-rail-signal.md +352 -0
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/mono-grid-signal.md +386 -0
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/ribbon-ledger-lift.md +384 -0
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/segmented-meter-clarity.md +388 -0
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/split-rail-precision.md +341 -0
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/status-framed-media-grid.md +361 -0
- package/yida-skills/skills/yida-design/workflow/output-design.md +375 -117
- package/yida-skills/skills/yida-design/workflow/output-prd.md +185 -0
- package/yida-skills/skills/yida-design/workflow/step-1-read-brief.md +1 -1
- package/yida-skills/skills/yida-design/workflow/step-2-theme-system.md +29 -33
- package/yida-skills/skills/yida-design/workflow/step-4-wireframe-interaction.md +1 -3
- package/yida-skills/skills/yida-design/workflow/step-5-visual-states.md +106 -22
- package/yida-skills/skills/yida-design/workflow/step-6-handoff.md +22 -15
- package/yida-skills/skills/yida-form-permission/SKILL.md +0 -6
- package/yida-skills/skills/yida-image-assets/SKILL.md +50 -73
- package/yida-skills/skills/yida-image-assets/references/manifest-contract.md +52 -82
- package/yida-skills/skills/yida-image-assets/references/source-policy.md +15 -14
- package/yida-skills/skills/yida-integration/SKILL.md +0 -1
- package/yida-skills/skills/yida-login/SKILL.md +0 -2
- package/yida-skills/skills/yida-nav-group/SKILL.md +2 -4
- package/yida-skills/skills/yida-nav-shell/SKILL.md +12 -36
- package/yida-skills/skills/yida-nav-shell/references/nav-shell-patterns.md +136 -79
- package/yida-skills/skills/yida-page-config/SKILL.md +4 -13
- package/yida-skills/skills/yida-prd/SKILL.md +3 -5
- package/yida-skills/skills/yida-prd/references/app/blueprint.md +4 -4
- package/yida-skills/skills/yida-prd/references/app/navigation-patterns.md +3 -6
- package/yida-skills/skills/yida-prd/references/app/role-journey.md +3 -5
- package/yida-skills/skills/yida-prd/references/plan-content.md +0 -4
- package/yida-skills/skills/yida-prd/workflow/output-prd.md +11 -18
- package/yida-skills/skills/yida-prd/workflow/plan-business.md +4 -4
- package/yida-skills/skills/yida-prd/workflow/step-2-information-architecture.md +8 -11
- package/yida-skills/skills/yida-publish-page/SKILL.md +1 -9
- package/yida-skills/skills/yida-requirement-analysis/SKILL.md +39 -10
- package/yida-skills/skills/yida-requirement-analysis/workflow/prepare-brief.md +71 -40
- package/yida-skills/skills-index.json +16 -36
- package/lib/app/application-entry-urls.js +0 -31
- package/lib/app/application-style.js +0 -69
- package/lib/app/canvas-icon-exports.json +0 -6160
- package/lib/app/canvas-icon-guard.js +0 -87
- package/lib/app/canvas-navigation-guard.js +0 -84
- package/lib/app/canvas-path-guard.js +0 -78
- package/lib/app/canvas-theme-guard.js +0 -184
- package/lib/app/form-data-response-guard.js +0 -57
- package/lib/asset/asset-execution.js +0 -79
- package/lib/core/css-structure.js +0 -37
- package/lib/design/check-design.js +0 -51
- package/lib/design/document.js +0 -458
- package/lib/design/icon-contrast.js +0 -85
- package/lib/design/page-content.js +0 -11
- package/lib/design-plan/artifact-updates.js +0 -117
- package/lib/design-plan/confirmation.js +0 -13
- package/lib/design-plan/entry-navigation.js +0 -97
- package/lib/design-plan/navigation-policy.js +0 -38
- package/lib/design-plan/rebase.js +0 -60
- package/lib/design-plan/themes.js +0 -101
- package/lib/design-plan/visual-policy.js +0 -42
- package/lib/samples/openyida-scaffold/canvas-admin-entry.jsx +0 -62
- package/lib/samples/openyida-scaffold/canvas-navigation.jsx +0 -56
- package/lib/samples/openyida-scaffold/canvas-view-state.jsx +0 -74
- package/yida-skills/skills/yida-app/references/entry-navigation.md +0 -193
- package/yida-skills/skills/yida-canvas-custom-page/references/view-state-recovery.md +0 -52
- package/yida-skills/skills/yida-canvas-data-binding/references/business-action-permissions.md +0 -31
- package/yida-skills/skills/yida-design/references/application-style-library.md +0 -93
- package/yida-skills/skills/yida-design/references/application-theme-consistency.md +0 -150
- package/yida-skills/skills/yida-design/references/native-form-styles.md +0 -208
- package/yida-skills/skills/yida-design/references/navigation-decision.md +0 -53
- package/yida-skills/skills/yida-design/references/page-continuity.md +0 -42
- package/yida-skills/skills/yida-design/references/theme/application-style-recipes.css +0 -58
- package/yida-skills/skills/yida-design/references/theme-selection.md +0 -67
- package/yida-skills/skills/yida-design/scripts/validate_design_themes.py +0 -302
- package/yida-skills/skills/yida-design/templates/application-styles.json +0 -398
- package/yida-skills/skills/yida-design/templates/design-themes/README.md +0 -73
- package/yida-skills/skills/yida-design/templates/design-themes/app-amber/app_theme.css +0 -748
- package/yida-skills/skills/yida-design/templates/design-themes/app-amber/design.md +0 -274
- package/yida-skills/skills/yida-design/templates/design-themes/app-amber/form-layout.json +0 -15
- package/yida-skills/skills/yida-design/templates/design-themes/app-editorial/app_theme.css +0 -748
- package/yida-skills/skills/yida-design/templates/design-themes/app-editorial/design.md +0 -274
- package/yida-skills/skills/yida-design/templates/design-themes/app-editorial/form-layout.json +0 -14
- package/yida-skills/skills/yida-design/templates/design-themes/app-executive/app_theme.css +0 -748
- package/yida-skills/skills/yida-design/templates/design-themes/app-executive/design.md +0 -274
- package/yida-skills/skills/yida-design/templates/design-themes/app-executive/form-layout.json +0 -13
- package/yida-skills/skills/yida-design/templates/design-themes/app-finance/app_theme.css +0 -748
- package/yida-skills/skills/yida-design/templates/design-themes/app-finance/design.md +0 -274
- package/yida-skills/skills/yida-design/templates/design-themes/app-finance/form-layout.json +0 -14
- package/yida-skills/skills/yida-design/templates/design-themes/app-glass/app_theme.css +0 -748
- package/yida-skills/skills/yida-design/templates/design-themes/app-glass/design.md +0 -274
- package/yida-skills/skills/yida-design/templates/design-themes/app-glass/form-layout.json +0 -14
- package/yida-skills/skills/yida-design/templates/design-themes/app-graphite/app_theme.css +0 -748
- package/yida-skills/skills/yida-design/templates/design-themes/app-graphite/design.md +0 -274
- package/yida-skills/skills/yida-design/templates/design-themes/app-graphite/form-layout.json +0 -14
- package/yida-skills/skills/yida-design/templates/design-themes/app-line/app_theme.css +0 -748
- package/yida-skills/skills/yida-design/templates/design-themes/app-line/design.md +0 -274
- package/yida-skills/skills/yida-design/templates/design-themes/app-line/form-layout.json +0 -13
- package/yida-skills/skills/yida-design/templates/design-themes/app-neon/app_theme.css +0 -748
- package/yida-skills/skills/yida-design/templates/design-themes/app-neon/design.md +0 -274
- package/yida-skills/skills/yida-design/templates/design-themes/app-neon/form-layout.json +0 -14
- package/yida-skills/skills/yida-design/templates/design-themes/app-nordic/app_theme.css +0 -754
- package/yida-skills/skills/yida-design/templates/design-themes/app-nordic/design.md +0 -279
- package/yida-skills/skills/yida-design/templates/design-themes/app-nordic/form-layout.json +0 -13
- package/yida-skills/skills/yida-design/templates/design-themes/app-paper/app_theme.css +0 -748
- package/yida-skills/skills/yida-design/templates/design-themes/app-paper/design.md +0 -274
- package/yida-skills/skills/yida-design/templates/design-themes/app-paper/form-layout.json +0 -13
- package/yida-skills/skills/yida-design/templates/design-themes/app-platinum/app_theme.css +0 -748
- package/yida-skills/skills/yida-design/templates/design-themes/app-platinum/design.md +0 -274
- package/yida-skills/skills/yida-design/templates/design-themes/app-platinum/form-layout.json +0 -14
- package/yida-skills/skills/yida-design/templates/design-themes/app-plum/app_theme.css +0 -748
- package/yida-skills/skills/yida-design/templates/design-themes/app-plum/design.md +0 -274
- package/yida-skills/skills/yida-design/templates/design-themes/app-plum/form-layout.json +0 -14
- package/yida-skills/skills/yida-design/templates/design-themes/app-pop/app_theme.css +0 -758
- package/yida-skills/skills/yida-design/templates/design-themes/app-pop/design.md +0 -281
- package/yida-skills/skills/yida-design/templates/design-themes/app-pop/form-layout.json +0 -14
- package/yida-skills/skills/yida-design/templates/design-themes/app-sage/app_theme.css +0 -748
- package/yida-skills/skills/yida-design/templates/design-themes/app-sage/design.md +0 -274
- package/yida-skills/skills/yida-design/templates/design-themes/app-sage/form-layout.json +0 -14
- package/yida-skills/skills/yida-design/templates/design-themes/app-teal/app_theme.css +0 -748
- package/yida-skills/skills/yida-design/templates/design-themes/app-teal/design.md +0 -274
- package/yida-skills/skills/yida-design/templates/design-themes/app-teal/form-layout.json +0 -14
- package/yida-skills/skills/yida-design/templates/design-themes/app-terminal/app_theme.css +0 -754
- package/yida-skills/skills/yida-design/templates/design-themes/app-terminal/design.md +0 -279
- package/yida-skills/skills/yida-design/templates/design-themes/app-terminal/form-layout.json +0 -14
- package/yida-skills/skills/yida-design/templates/design-themes/app-ticket/app_theme.css +0 -752
- package/yida-skills/skills/yida-design/templates/design-themes/app-ticket/design.md +0 -278
- package/yida-skills/skills/yida-design/templates/design-themes/app-ticket/form-layout.json +0 -13
- package/yida-skills/skills/yida-design/templates/design-themes/app-wire/app_theme.css +0 -748
- package/yida-skills/skills/yida-design/templates/design-themes/app-wire/design.md +0 -274
- package/yida-skills/skills/yida-design/templates/design-themes/app-wire/form-layout.json +0 -14
- package/yida-skills/skills/yida-design/templates/design-themes/basic-tokens.json +0 -118
- package/yida-skills/skills/yida-design/templates/design-themes/dark-inset-hairline/app_theme.css +0 -690
- package/yida-skills/skills/yida-design/templates/design-themes/dark-inset-hairline/design.md +0 -382
- package/yida-skills/skills/yida-design/templates/design-themes/dark-inset-hairline/form-layout.json +0 -13
- package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-fine-lines/app_theme.css +0 -691
- package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-fine-lines/design.md +0 -380
- package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-fine-lines/form-layout.json +0 -13
- package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-signal-panels/app_theme.css +0 -696
- package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-signal-panels/design.md +0 -378
- package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-signal-panels/form-layout.json +0 -13
- package/yida-skills/skills/yida-design/templates/design-themes/free-creative/app_theme.css +0 -689
- package/yida-skills/skills/yida-design/templates/design-themes/free-creative/design.md +0 -238
- package/yida-skills/skills/yida-design/templates/design-themes/free-creative/form-layout.json +0 -13
- package/yida-skills/skills/yida-design/templates/design-themes/graphite-bevel-grid/app_theme.css +0 -692
- package/yida-skills/skills/yida-design/templates/design-themes/graphite-bevel-grid/design.md +0 -375
- package/yida-skills/skills/yida-design/templates/design-themes/graphite-bevel-grid/form-layout.json +0 -13
- package/yida-skills/skills/yida-design/templates/design-themes/hairline-shared-bands/app_theme.css +0 -691
- package/yida-skills/skills/yida-design/templates/design-themes/hairline-shared-bands/design.md +0 -362
- package/yida-skills/skills/yida-design/templates/design-themes/hairline-shared-bands/form-layout.json +0 -13
- package/yida-skills/skills/yida-design/templates/design-themes/hairline-soft-blocks/app_theme.css +0 -691
- package/yida-skills/skills/yida-design/templates/design-themes/hairline-soft-blocks/design.md +0 -409
- package/yida-skills/skills/yida-design/templates/design-themes/hairline-soft-blocks/form-layout.json +0 -13
- package/yida-skills/skills/yida-design/templates/design-themes/index.json +0 -464
- package/yida-skills/skills/yida-design/templates/design-themes/ink-glow-soft-panels/app_theme.css +0 -701
- package/yida-skills/skills/yida-design/templates/design-themes/ink-glow-soft-panels/design.md +0 -379
- package/yida-skills/skills/yida-design/templates/design-themes/ink-glow-soft-panels/form-layout.json +0 -13
- package/yida-skills/skills/yida-design/templates/design-themes/inset-frame-pixel-rhythm/app_theme.css +0 -691
- package/yida-skills/skills/yida-design/templates/design-themes/inset-frame-pixel-rhythm/design.md +0 -404
- package/yida-skills/skills/yida-design/templates/design-themes/inset-frame-pixel-rhythm/form-layout.json +0 -13
- package/yida-skills/skills/yida-design/templates/design-themes/outlined-texture-duotone/app_theme.css +0 -698
- package/yida-skills/skills/yida-design/templates/design-themes/outlined-texture-duotone/design.md +0 -389
- package/yida-skills/skills/yida-design/templates/design-themes/outlined-texture-duotone/form-layout.json +0 -13
- package/yida-skills/skills/yida-design/templates/design-themes/soft-inset-surfaces/app_theme.css +0 -691
- package/yida-skills/skills/yida-design/templates/design-themes/soft-inset-surfaces/design.md +0 -372
- package/yida-skills/skills/yida-design/templates/design-themes/soft-inset-surfaces/form-layout.json +0 -13
- package/yida-skills/skills/yida-design/templates/design-themes/soft-outline-rhythm/app_theme.css +0 -690
- package/yida-skills/skills/yida-design/templates/design-themes/soft-outline-rhythm/design.md +0 -455
- package/yida-skills/skills/yida-design/templates/design-themes/soft-outline-rhythm/form-layout.json +0 -13
- package/yida-skills/skills/yida-design/templates/design-themes/soft-rail-bold-band/app_theme.css +0 -698
- package/yida-skills/skills/yida-design/templates/design-themes/soft-rail-bold-band/design.md +0 -394
- package/yida-skills/skills/yida-design/templates/design-themes/soft-rail-bold-band/form-layout.json +0 -13
- package/yida-skills/skills/yida-design/templates/design-themes/soft-spectral-panels/app_theme.css +0 -692
- package/yida-skills/skills/yida-design/templates/design-themes/soft-spectral-panels/design.md +0 -391
- package/yida-skills/skills/yida-design/templates/design-themes/soft-spectral-panels/form-layout.json +0 -13
- package/yida-skills/skills/yida-design/templates/design-themes/warm-canvas-contrast-panels/app_theme.css +0 -711
- package/yida-skills/skills/yida-design/templates/design-themes/warm-canvas-contrast-panels/design.md +0 -408
- package/yida-skills/skills/yida-design/templates/design-themes/warm-canvas-contrast-panels/form-layout.json +0 -13
- package/yida-skills/skills/yida-design/templates/design-themes/warm-rail-muted-panels/app_theme.css +0 -692
- package/yida-skills/skills/yida-design/templates/design-themes/warm-rail-muted-panels/design.md +0 -383
- package/yida-skills/skills/yida-design/templates/design-themes/warm-rail-muted-panels/form-layout.json +0 -13
- package/yida-skills/skills/yida-design/templates/navigation-styles.json +0 -769
- package/yida-skills/skills/yida-requirement-analysis/references/experience-groups.md +0 -79
- package/yida-skills/skills/yida-requirement-analysis/references/handoff.md +0 -68
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const { CliError } = require('../core/cli-error');
|
|
6
|
-
const { t } = require('../core/i18n');
|
|
7
|
-
const { readJson } = require('./files');
|
|
8
|
-
|
|
9
|
-
const STATE_FILE = '.build-plan-artifacts.json';
|
|
10
|
-
const DOCUMENTS = new Set(['prd.md', 'design.md', 'build-plan.html']);
|
|
11
|
-
|
|
12
|
-
function conflict(file, section) {
|
|
13
|
-
throw new CliError(t('design_document.update_conflict', file, section), {
|
|
14
|
-
code: 'DESIGN_PLAN_UPDATE_CONFLICT', details: { file, section },
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Fixed chapter numbers and HTML section IDs survive changes to display titles.
|
|
19
|
-
function blocks(content, html) {
|
|
20
|
-
const starts = [{ key: 'header', index: 0 }];
|
|
21
|
-
if (html) {
|
|
22
|
-
for (const match of content.matchAll(/<section id="(overview|data-models|business-flows|pages)" class="page-section">/g)) {
|
|
23
|
-
starts.push({ key: match[1], index: match.index });
|
|
24
|
-
}
|
|
25
|
-
const end = content.lastIndexOf('</article>');
|
|
26
|
-
if (end >= 0) {starts.push({ key: 'footer', index: end });}
|
|
27
|
-
} else {
|
|
28
|
-
const frontmatter = /^---\r?\n[\s\S]*?\r?\n---\r?\n/.exec(content);
|
|
29
|
-
if (frontmatter) {starts.push({ key: 'intro', index: frontmatter[0].length });}
|
|
30
|
-
let offset = 0, fence = null;
|
|
31
|
-
for (const line of content.split(/(?<=\n)/)) {
|
|
32
|
-
const marker = /^\s{0,3}(`{3,}|~{3,})/.exec(line);
|
|
33
|
-
if (marker) {
|
|
34
|
-
if (!fence) {fence = marker[1];}
|
|
35
|
-
else if (marker[1][0] === fence[0] && marker[1].length >= fence.length) {fence = null;}
|
|
36
|
-
} else if (!fence) {
|
|
37
|
-
const heading = /^## (\d+)\. /.exec(line);
|
|
38
|
-
if (heading) {starts.push({ key: `chapter-${heading[1]}`, index: offset });}
|
|
39
|
-
}
|
|
40
|
-
offset += line.length;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return starts.map((entry, index) => ({ ...entry, end: starts[index + 1]?.index ?? content.length,
|
|
44
|
-
text: content.slice(entry.index, starts[index + 1]?.index) }));
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function updateBlock(before, after, current, file, key) {
|
|
48
|
-
if (current === before || current === after) {return after;}
|
|
49
|
-
const oldLines = before.split(/(?<=\n)/), newLines = after.split(/(?<=\n)/);
|
|
50
|
-
let start = 0, end = oldLines.length, nextEnd = newLines.length;
|
|
51
|
-
while (start < end && start < nextEnd && oldLines[start] === newLines[start]) {start++;}
|
|
52
|
-
while (end > start && nextEnd > start && oldLines[end - 1] === newLines[nextEnd - 1]) {end--; nextEnd--;}
|
|
53
|
-
const contextStart = Math.max(0, start - 3);
|
|
54
|
-
const contextEnd = Math.min(oldLines.length, end + 3);
|
|
55
|
-
const needle = oldLines.slice(contextStart, contextEnd).join('');
|
|
56
|
-
const replacement = [...oldLines.slice(contextStart, start), ...newLines.slice(start, nextEnd), ...oldLines.slice(end, contextEnd)].join('');
|
|
57
|
-
const position = current.indexOf(needle);
|
|
58
|
-
if (!needle || position < 0 || current.indexOf(needle, position + 1) >= 0) {conflict(file, key);}
|
|
59
|
-
return current.slice(0, position) + replacement + current.slice(position + needle.length);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function mergeDocument(before, after, current, file) {
|
|
63
|
-
if (before === after || current === after) {return current;}
|
|
64
|
-
if (current === before) {return after;}
|
|
65
|
-
const html = file.endsWith('.html');
|
|
66
|
-
const oldBlocks = blocks(before, html), newBlocks = blocks(after, html), currentBlocks = blocks(current, html);
|
|
67
|
-
for (const list of [oldBlocks, newBlocks, currentBlocks]) {
|
|
68
|
-
if (new Set(list.map(block => block.key)).size !== list.length) {conflict(file, 'structure');}
|
|
69
|
-
}
|
|
70
|
-
if (oldBlocks.map(block => block.key).join() !== newBlocks.map(block => block.key).join()) {conflict(file, 'structure');}
|
|
71
|
-
const edits = [];
|
|
72
|
-
for (let index = 0; index < oldBlocks.length; index++) {
|
|
73
|
-
const beforeBlock = oldBlocks[index], afterBlock = newBlocks[index];
|
|
74
|
-
if (beforeBlock.text === afterBlock.text) {continue;}
|
|
75
|
-
const currentBlock = currentBlocks.find(block => block.key === beforeBlock.key);
|
|
76
|
-
if (!currentBlock) {conflict(file, beforeBlock.key);}
|
|
77
|
-
edits.push({ ...currentBlock, text: updateBlock(beforeBlock.text, afterBlock.text, currentBlock.text, file, beforeBlock.key) });
|
|
78
|
-
}
|
|
79
|
-
let result = current;
|
|
80
|
-
for (const edit of edits.sort((a, b) => b.index - a.index)) {
|
|
81
|
-
result = result.slice(0, edit.index) + edit.text + result.slice(edit.end);
|
|
82
|
-
}
|
|
83
|
-
return result;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Keep the last generated text separate from local edits, so later source changes
|
|
87
|
-
// can update their own sections without treating local notes as generated content.
|
|
88
|
-
function prepareUpdates(artifacts, outputDir, previousArtifacts) {
|
|
89
|
-
const statePath = path.join(outputDir, STATE_FILE);
|
|
90
|
-
let baseline = {};
|
|
91
|
-
if (fs.existsSync(statePath)) {
|
|
92
|
-
const state = readJson(statePath, STATE_FILE);
|
|
93
|
-
if (state.version !== 1 || !state.documents || typeof state.documents !== 'object') {conflict(statePath, 'baseline');}
|
|
94
|
-
baseline = state.documents;
|
|
95
|
-
} else if (previousArtifacts && artifacts.files.some(([file]) => DOCUMENTS.has(path.basename(file)) && fs.existsSync(file))) {
|
|
96
|
-
baseline = Object.fromEntries(previousArtifacts().files.filter(([file]) => DOCUMENTS.has(path.basename(file))).map(([file, content]) => [path.basename(file), content]));
|
|
97
|
-
}
|
|
98
|
-
const documents = {}, files = [], updated = [];
|
|
99
|
-
for (const [file, generated] of artifacts.files) {
|
|
100
|
-
const name = path.basename(file);
|
|
101
|
-
const current = fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : undefined;
|
|
102
|
-
let content = generated;
|
|
103
|
-
if (DOCUMENTS.has(name)) {
|
|
104
|
-
documents[name] = generated;
|
|
105
|
-
if (current !== undefined && current !== generated) {
|
|
106
|
-
if (typeof baseline[name] !== 'string') {conflict(file, 'baseline');}
|
|
107
|
-
content = mergeDocument(baseline[name], generated, current, file);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
if (content !== current) {files.push([file, content]); updated.push(file);}
|
|
111
|
-
}
|
|
112
|
-
const state = JSON.stringify({ version: 1, documents }, null, 2) + '\n';
|
|
113
|
-
if (!fs.existsSync(statePath) || fs.readFileSync(statePath, 'utf8') !== state) {files.push([statePath, state]);}
|
|
114
|
-
return { files, updated, previousDesign: baseline['design.md'] };
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
module.exports = { prepareUpdates, mergeDocument };
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
function confirmationPayload(outputs, revision) {
|
|
4
|
-
return {
|
|
5
|
-
question: '请确认当前搭建方案',
|
|
6
|
-
options: [{ label: '确认并开始搭建', value: 'confirm_build' }, { label: '继续调整', value: 'continue_editing' }],
|
|
7
|
-
submitLabel: '提交选择',
|
|
8
|
-
attachments: [{ name: '搭建方案.html', path: outputs.html }],
|
|
9
|
-
revision,
|
|
10
|
-
};
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
module.exports = { confirmationPayload };
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { CliError } = require('../core/cli-error');
|
|
4
|
-
const { t } = require('../core/i18n');
|
|
5
|
-
const ENTRY_MODES = Object.freeze(['unified', 'service-management', 'frontend-only', 'backend-only']);
|
|
6
|
-
const ENTRY_MODE_SUMMARIES = Object.freeze({
|
|
7
|
-
unified: '不分前后台:使用同一套业务页面,按职责显示菜单、数据和操作。',
|
|
8
|
-
'service-management': '分前后台:办事的人使用前台,处理业务的人使用后台,两边共享业务数据。',
|
|
9
|
-
'frontend-only': '只有访问前台:本次提供办理、查询或展示页面;需要处理的业务由已有系统、人员入口或自动流程承接。',
|
|
10
|
-
'backend-only': '只有访问后台:工作人员录入、受理、处理或维护业务,办事入口在别处或本次不需要。',
|
|
11
|
-
});
|
|
12
|
-
const filled = value => typeof value === 'string' && value.trim().length > 0;
|
|
13
|
-
const object = value => value && typeof value === 'object' && !Array.isArray(value);
|
|
14
|
-
const assert = (condition, message, details) => {
|
|
15
|
-
if (!condition) {throw new CliError(message, { code: 'DESIGN_PLAN_INVALID_ENTRY_NAVIGATION', ...(details ? { details } : {}) });}
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
// Resource names are planning references. Runtime IDs and permissions are resolved after creation.
|
|
19
|
-
function buildEntryNavigation(plan, resources, pages) {
|
|
20
|
-
const recommendation = plan.execution?.entryRecommendation;
|
|
21
|
-
if (recommendation === undefined) {return null;}
|
|
22
|
-
assert(object(recommendation) && ENTRY_MODES.includes(recommendation.mode), t('cli.design_plan_entry_mode_required'));
|
|
23
|
-
assert(Array.isArray(recommendation.entries) && recommendation.entries.length > 0, '入口方案缺少 entries');
|
|
24
|
-
const names = new Set(resources.map(resource => resource.name));
|
|
25
|
-
const entryKeys = new Set();
|
|
26
|
-
const platformOrder = [];
|
|
27
|
-
for (const entry of recommendation.entries) {
|
|
28
|
-
assert(object(entry) && filled(entry.key) && !entryKeys.has(entry.key) && filled(entry.name), '入口 key/name 缺失或重复');
|
|
29
|
-
entryKeys.add(entry.key);
|
|
30
|
-
assert(['service', 'management', 'workspace'].includes(entry.role), `入口 ${entry.name} 需要明确业务身份`);
|
|
31
|
-
const page = filled(entry.sceneKey) ? pages.find(item => item.sceneKey === entry.sceneKey) : undefined;
|
|
32
|
-
assert(entry.sceneKey === undefined || page, `入口 ${entry.name} 引用了未知 sceneKey`);
|
|
33
|
-
assert(entry.sceneKey === undefined || pages.filter(item => item.sceneKey === entry.sceneKey).length === 1, `入口 ${entry.name} 的 sceneKey 必须唯一关联页面`);
|
|
34
|
-
if (entry.role === 'service') {
|
|
35
|
-
assert(page?.pageSpecHandoff.entryMode === 'standalone', `访客入口 ${entry.name} 必须关联独立页面`);
|
|
36
|
-
}
|
|
37
|
-
assert(Array.isArray(entry.menu) && entry.menu.length > 0, `入口 ${entry.name} 缺少任务菜单,单步入口也需记录唯一任务`);
|
|
38
|
-
const keys = new Set();
|
|
39
|
-
const leaves = [];
|
|
40
|
-
const visit = items => {
|
|
41
|
-
for (const item of items) {
|
|
42
|
-
assert(object(item) && filled(item.key) && !keys.has(item.key) && filled(item.label), `入口 ${entry.name} 的菜单 key/label 缺失或重复`);
|
|
43
|
-
keys.add(item.key);
|
|
44
|
-
if (item.children !== undefined) {
|
|
45
|
-
assert(Array.isArray(item.children) && item.children.length > 0, `菜单 ${item.label} 的分组为空`);
|
|
46
|
-
visit(item.children);
|
|
47
|
-
continue;
|
|
48
|
-
}
|
|
49
|
-
assert(names.has(item.resource), `菜单 ${item.label} 引用了未知资源`);
|
|
50
|
-
assert(['local', 'submission', 'page', 'custom'].includes(item.targetType), `菜单 ${item.label} 缺少入口用途`);
|
|
51
|
-
if (item.targetType === 'submission') {
|
|
52
|
-
assert(resources.some(resource => resource.name === item.resource && ['normal-form', 'process-form'].includes(resource.type)), `菜单 ${item.label} 的提交目标必须是表单`);
|
|
53
|
-
}
|
|
54
|
-
assert(item.viewUuid === undefined || (filled(item.viewUuid) && item.targetType === 'page'), `菜单 ${item.label} 的 viewUuid 仅用于真实管理视图`);
|
|
55
|
-
const targetPage = pages.find(candidate => candidate.name === item.resource);
|
|
56
|
-
if (item.targetType === 'local') {
|
|
57
|
-
const missingFields = [!filled(entry.sceneKey) && 'entry.sceneKey',
|
|
58
|
-
(page && item.resource !== page.name) && 'menu.resource', !filled(item.viewKey) && 'menu.viewKey'].filter(Boolean);
|
|
59
|
-
assert(filled(entry.sceneKey) && page && item.resource === page.name && filled(item.viewKey),
|
|
60
|
-
t('cli.design_plan_local_menu_binding', item.label, entry.name),
|
|
61
|
-
{ entryKey: entry.key, menuKey: item.key, sceneKey: entry.sceneKey || null,
|
|
62
|
-
pageName: page?.name || null, resource: item.resource, missingFields });
|
|
63
|
-
}
|
|
64
|
-
if (item.targetType === 'custom') {
|
|
65
|
-
assert(targetPage?.pageSpecHandoff.entryMode === 'standalone', `菜单 ${item.label} 的 custom 目标必须为独立页面`);
|
|
66
|
-
}
|
|
67
|
-
if (item.targetType === 'page') {
|
|
68
|
-
assert(targetPage?.pageSpecHandoff.entryMode !== 'standalone', `菜单 ${item.label} 应使用 custom 路径打开独立页面,避免双导航`);
|
|
69
|
-
}
|
|
70
|
-
assert(Array.isArray(item.access) && item.access.length > 0, `菜单 ${item.label} 缺少权限依赖`);
|
|
71
|
-
for (const requirement of item.access) {
|
|
72
|
-
assert(object(requirement) && names.has(requirement.resource) && filled(requirement.operation)
|
|
73
|
-
&& filled(requirement.dataScope), `菜单 ${item.label} 需填写权限资源、操作和数据范围`);
|
|
74
|
-
assert(requirement.viewUuid === undefined || filled(requirement.viewUuid), `菜单 ${item.label} 的权限视图无效`);
|
|
75
|
-
}
|
|
76
|
-
const operation = item.targetType === 'submission' ? 'OPERATE_CREATE' : 'OPERATE_VIEW';
|
|
77
|
-
assert(item.access.some(requirement => requirement.resource === item.resource && requirement.operation === operation
|
|
78
|
-
&& (requirement.viewUuid || '') === (item.viewUuid || '')), `菜单 ${item.label} 缺少目标用途对应的 ${operation} 权限`);
|
|
79
|
-
leaves.push(item);
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
visit(entry.menu);
|
|
83
|
-
assert(leaves.some(item => item.key === entry.defaultMenuKey), `入口 ${entry.name} 的默认菜单必须指向有效任务`);
|
|
84
|
-
if (entry.role !== 'service') {
|
|
85
|
-
const first = leaves.find(item => item.key === entry.defaultMenuKey);
|
|
86
|
-
assert(first.targetType !== 'custom', `管理入口 ${entry.name} 不能默认跳到独立前台`);
|
|
87
|
-
platformOrder.push(first.resource, ...leaves.filter(item => item.targetType !== 'custom').map(item => item.resource));
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
const roles = recommendation.entries.map(entry => entry.role);
|
|
91
|
-
assert(recommendation.mode !== 'service-management' || (roles.includes('service') && roles.includes('management')), '前后台方案必须同时包含访客端和业务管理端');
|
|
92
|
-
assert(recommendation.mode !== 'frontend-only' || roles.every(role => role === 'service'), '仅前台方案不能包含管理入口');
|
|
93
|
-
assert(recommendation.mode !== 'backend-only' || roles.every(role => role === 'management'), t('cli.design_plan_backend_only_roles'));
|
|
94
|
-
return { recommendation: JSON.parse(JSON.stringify(recommendation)), platformOrder: [...new Set(platformOrder)] };
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
module.exports = { buildEntryNavigation, ENTRY_MODES, ENTRY_MODE_SUMMARIES };
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// Shared by the materialized page handoff and CLI manifest. This is an output
|
|
4
|
-
// contract, not a new authoring field or a claim about the live platform config.
|
|
5
|
-
function getPageNavigationContract() {
|
|
6
|
-
return {
|
|
7
|
-
output_path: 'pages[].navigationPolicy in the PRD execution handoff',
|
|
8
|
-
input_policy: 'Derived from app navigation and pageSpecHandoff; do not write navigationPolicy into build-plan.json or page-spec.json.',
|
|
9
|
-
platform_shell: {
|
|
10
|
-
applicationMenuOwner: 'platform', pageLayout: 'content-only',
|
|
11
|
-
renderApplicationMenu: false, localTabs: 'same-task-only', duplicatePlatformMenu: false,
|
|
12
|
-
},
|
|
13
|
-
page_owned: {
|
|
14
|
-
applicationMenuOwner: 'page', pageLayout: 'standalone',
|
|
15
|
-
renderApplicationMenu: true, localTabs: 'planned-views', duplicatePlatformMenu: false,
|
|
16
|
-
},
|
|
17
|
-
no_menu: {
|
|
18
|
-
applicationMenuOwner: 'none', pageLayout: 'standalone',
|
|
19
|
-
renderApplicationMenu: false, localTabs: 'same-task-only', duplicatePlatformMenu: false,
|
|
20
|
-
},
|
|
21
|
-
selection: 'platform-shell uses platform_shell; standalone uses page_owned only for explicit custom page menus or application custom navigation. Explicit none and standalone without a planned menu use no_menu.',
|
|
22
|
-
discussion: {
|
|
23
|
-
plan: 'Include frontend and workspace navigation in the overall plan discussion and confirmation; material changes follow the existing revision confirmation workflow.',
|
|
24
|
-
fast: 'Explain and use the recorded decision; no additional navigation approval gate.',
|
|
25
|
-
existing: 'Preserve explicit user requirements and existing navigation for local changes; page Tabs or state preservation alone do not authorize replacing platform navigation.',
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function buildPageNavigationPolicy(spec, applicationNavigationType) {
|
|
31
|
-
const contract = getPageNavigationContract();
|
|
32
|
-
if (spec.entryMode === 'platform-shell') { return contract.platform_shell; }
|
|
33
|
-
if (spec.navigation?.type === 'none') { return contract.no_menu; }
|
|
34
|
-
return spec.navigation?.type === 'custom' || applicationNavigationType === 'custom'
|
|
35
|
-
? contract.page_owned : contract.no_menu;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
module.exports = { getPageNavigationContract, buildPageNavigationPolicy };
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const fs = require('fs');
|
|
5
|
-
const { CliError } = require('../core/cli-error');
|
|
6
|
-
const { readJson } = require('./files');
|
|
7
|
-
const { t } = require('../core/i18n');
|
|
8
|
-
|
|
9
|
-
const BASE_FILE = '.build-plan-base.json';
|
|
10
|
-
const equal = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
11
|
-
const object = value => value && typeof value === 'object' && !Array.isArray(value);
|
|
12
|
-
|
|
13
|
-
// Arrays represent ordered business facts; conflicting edits require a decision.
|
|
14
|
-
function reconcile(base, current, proposed, field, conflicts) {
|
|
15
|
-
if (equal(current, proposed) || equal(proposed, base)) { return current; }
|
|
16
|
-
if (equal(current, base)) { return proposed; }
|
|
17
|
-
if (object(base) && object(current) && object(proposed)) {
|
|
18
|
-
const result = {};
|
|
19
|
-
for (const key of new Set([...Object.keys(base), ...Object.keys(current), ...Object.keys(proposed)])) {
|
|
20
|
-
const value = reconcile(base[key], current[key], proposed[key], field ? `${field}.${key}` : key, conflicts);
|
|
21
|
-
if (value !== undefined) { result[key] = value; }
|
|
22
|
-
}
|
|
23
|
-
return result;
|
|
24
|
-
}
|
|
25
|
-
conflicts.push(field);
|
|
26
|
-
return proposed;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function rebaseParts(source, input, businessFile, visualFile) {
|
|
30
|
-
const { planBase } = require('./parallel');
|
|
31
|
-
const baselinePath = path.join(path.dirname(path.resolve(input)), BASE_FILE);
|
|
32
|
-
const fail = (code, details) => { throw new CliError(t('design_plan.rebase_required'), { code, details: { baselinePath, ...details } }); };
|
|
33
|
-
if (!fs.existsSync(baselinePath)) { fail('DESIGN_PLAN_BASELINE_MISSING', { nextStep: t('design_plan.baseline_missing') }); }
|
|
34
|
-
const saved = readJson(baselinePath);
|
|
35
|
-
if (saved.schemaVersion !== 1 || !object(saved.plan) || !equal(saved.base, planBase(saved.plan))) {
|
|
36
|
-
fail('DESIGN_PLAN_BASELINE_INVALID', { nextStep: t('design_plan.baseline_missing') });
|
|
37
|
-
}
|
|
38
|
-
if (source.meta?.status !== 'draft' || source.meta?.planState?.presentedRevision
|
|
39
|
-
|| source.meta?.planState?.planConfirmed || !equal(source.meta, saved.plan.meta)) {
|
|
40
|
-
fail('DESIGN_PLAN_REBASE_STAGE_INVALID', { nextStep: t('design_plan.rebase_stage_invalid') });
|
|
41
|
-
}
|
|
42
|
-
const parts = [businessFile, visualFile].map(file => readJson(file));
|
|
43
|
-
for (const [index, part] of parts.entries()) {
|
|
44
|
-
if (!equal(part.base, saved.base) || !object(part.facts)) {
|
|
45
|
-
fail('DESIGN_PLAN_BASELINE_MISMATCH', { sourcePath: [businessFile, visualFile][index], nextStep: t('design_plan.baseline_missing') });
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
return parts.map((part, index) => {
|
|
49
|
-
const conflicts = [];
|
|
50
|
-
const facts = Object.fromEntries(Object.keys(part.facts).map(key => [key,
|
|
51
|
-
reconcile(saved.plan[key], source[key], part.facts[key], key, conflicts),
|
|
52
|
-
]));
|
|
53
|
-
if (conflicts.length) {
|
|
54
|
-
fail('DESIGN_PLAN_REBASE_CONFLICT', { sourcePath: [businessFile, visualFile][index], conflicts, nextStep: t('design_plan.rebase_conflict') });
|
|
55
|
-
}
|
|
56
|
-
return { ...part, facts, base: planBase(source) };
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
module.exports = { BASE_FILE, rebaseParts };
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const { CliError } = require('../core/cli-error');
|
|
6
|
-
const { readJson } = require('./files');
|
|
7
|
-
const { parseDesignDocument } = require('../design/document');
|
|
8
|
-
|
|
9
|
-
const DESIGN_SKILL_ROOT = path.resolve(__dirname, '../../yida-skills/skills/yida-design');
|
|
10
|
-
const PLAN_SKILL_ROOT = path.join(DESIGN_SKILL_ROOT, 'sub_skill/yida-design-plan');
|
|
11
|
-
const THEME_DIR = path.join(DESIGN_SKILL_ROOT, 'templates/design-themes');
|
|
12
|
-
|
|
13
|
-
function loadThemeIndex() {
|
|
14
|
-
return readJson(path.join(THEME_DIR, 'index.json'), '主题索引');
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function themeTemplatePath(theme) {
|
|
18
|
-
const file = path.resolve(DESIGN_SKILL_ROOT, theme.templatePath);
|
|
19
|
-
if (!file.startsWith(`${THEME_DIR}${path.sep}`) || !fs.existsSync(file)) {
|
|
20
|
-
throw new CliError(`主题模板不可读:${theme.templatePath}`, { code: 'DESIGN_PLAN_THEME_UNREADABLE' });
|
|
21
|
-
}
|
|
22
|
-
return file;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function themeNavTheme(theme) {
|
|
26
|
-
if (theme.mode === 'creative') {return undefined;}
|
|
27
|
-
const file = themeTemplatePath(theme);
|
|
28
|
-
const metadata = parseDesignDocument(fs.readFileSync(file, 'utf8')).metadata;
|
|
29
|
-
const navTheme = metadata.themeProfile?.navTheme || metadata.navTheme;
|
|
30
|
-
if (!['light', 'dark'].includes(navTheme)) {
|
|
31
|
-
throw new CliError(`主题模板 navTheme 无效:${theme.themeId}`, {
|
|
32
|
-
code: 'DESIGN_PLAN_THEME_NAV_THEME_INVALID',
|
|
33
|
-
details: { themeId: theme.themeId, navTheme: metadata.navTheme, templatePath: theme.templatePath },
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
return navTheme;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Color recipes live with the visual theme. Resolve their token dependencies rather
|
|
40
|
-
// than duplicating per-theme palettes in JavaScript.
|
|
41
|
-
function resolveThemeColors(source) {
|
|
42
|
-
const frontmatter = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/.exec(source);
|
|
43
|
-
const tokenSource = frontmatter ? frontmatter[1] : source;
|
|
44
|
-
const definitions = new Map([...tokenSource.matchAll(/^\s*"(--[\w-]+)":\s*"([^"\n]*)"/gm)]
|
|
45
|
-
.map(([, name, value]) => [name, value]));
|
|
46
|
-
const resolved = new Map();
|
|
47
|
-
const resolving = new Set();
|
|
48
|
-
const invalid = value => { throw new CliError(`主题色值无法生成:${value}`, { code: 'DESIGN_PLAN_THEME_COLOR_INVALID' }); };
|
|
49
|
-
function color(value) {
|
|
50
|
-
if (value.startsWith('--')) {return resolve(value);}
|
|
51
|
-
if (/^#[\da-f]{6}$/i.test(value)) {return value.toUpperCase();}
|
|
52
|
-
const alias = /^var\((--[\w-]+)(?:,\s*[^)]+)?\)$/.exec(value);
|
|
53
|
-
if (alias) {return resolve(alias[1]);}
|
|
54
|
-
return invalid(value);
|
|
55
|
-
}
|
|
56
|
-
function channels(value) {
|
|
57
|
-
const hex = color(value);
|
|
58
|
-
if (!/^#[\da-f]{6}$/i.test(hex)) {return invalid(value);}
|
|
59
|
-
return [1, 3, 5].map(index => parseInt(hex.slice(index, index + 2), 16));
|
|
60
|
-
}
|
|
61
|
-
function resolve(name) {
|
|
62
|
-
if (resolved.has(name)) {return resolved.get(name);}
|
|
63
|
-
if (resolving.has(name) || !definitions.has(name)) {return invalid(name);}
|
|
64
|
-
resolving.add(name);
|
|
65
|
-
const raw = definitions.get(name);
|
|
66
|
-
let result = raw;
|
|
67
|
-
if (raw.startsWith('<生成实际色值:')) {
|
|
68
|
-
const mix = /^<生成实际色值:(--[\w-]+|#[\da-f]{6}) (\d+(?:\.\d+)?)% \+ (--[\w-]+|#[\da-f]{6}) (\d+(?:\.\d+)?)%,sRGB 逐通道混合>$/i.exec(raw);
|
|
69
|
-
const alpha = /^<生成实际色值:取 (--[\w-]+) 的 sRGB 三通道,alpha 设为 (0(?:\.\d+)?|1(?:\.0+)?),输出 rgba>$/.exec(raw);
|
|
70
|
-
if (mix) {
|
|
71
|
-
const [, left, leftPercent, right, rightPercent] = mix;
|
|
72
|
-
if (Math.abs(Number(leftPercent) + Number(rightPercent) - 100) > 0.001) {return invalid(raw);}
|
|
73
|
-
const a = channels(left);
|
|
74
|
-
const b = channels(right);
|
|
75
|
-
result = `#${a.map((channel, index) => Math.round((channel * Number(leftPercent) + b[index] * Number(rightPercent)) / 100)
|
|
76
|
-
.toString(16).padStart(2, '0')).join('').toUpperCase()}`;
|
|
77
|
-
} else if (alpha) {
|
|
78
|
-
result = `rgba(${channels(alpha[1]).join(', ')}, ${alpha[2]})`;
|
|
79
|
-
} else {return invalid(raw);}
|
|
80
|
-
} else if (raw.startsWith('var(')) {
|
|
81
|
-
result = color(raw);
|
|
82
|
-
}
|
|
83
|
-
resolving.delete(name);
|
|
84
|
-
resolved.set(name, result);
|
|
85
|
-
return result;
|
|
86
|
-
}
|
|
87
|
-
const output = tokenSource.replace(/^(\s*"(--[\w-]+)":\s*)"(<生成实际色值:[^"\n]*>)"/gm,
|
|
88
|
-
(line, prefix, name) => `${prefix}"${resolve(name)}"`);
|
|
89
|
-
return frontmatter ? frontmatter[0].replace(frontmatter[1], () => output) + source.slice(frontmatter[0].length) : output;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function resolveColorToken(tokens, name, seen = new Set()) {
|
|
93
|
-
if (seen.has(name)) {return null;}
|
|
94
|
-
seen.add(name);
|
|
95
|
-
const value = tokens[name];
|
|
96
|
-
if (/^#[\da-f]{6}$/i.test(value || '')) {return value.toUpperCase();}
|
|
97
|
-
const alias = /^var\((--[\w-]+)(?:,\s*([^)]+))?\)$/.exec(value || '');
|
|
98
|
-
return alias ? resolveColorToken(tokens, alias[1], seen) || alias[2] || null : null;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
module.exports = { DESIGN_SKILL_ROOT, PLAN_SKILL_ROOT, loadThemeIndex, themeTemplatePath, themeNavTheme, resolveThemeColors, resolveColorToken };
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
function getVisualDecisionPolicy() {
|
|
4
|
-
return {
|
|
5
|
-
reference: 'yida-skills/skills/yida-design/references/theme-selection.md#设计方向比较',
|
|
6
|
-
preserve: 'explicit_user_direction_brand_and_existing_app_theme',
|
|
7
|
-
applicationStyle: {
|
|
8
|
-
scope: ['navigation', 'application_shell', 'native_form', 'custom_page', 'record_detail'],
|
|
9
|
-
navigationTokens: 'tokens.application-global.appearance.navigation',
|
|
10
|
-
navigationRoles: ['surface', 'text', 'hover', 'selected', 'disabled', 'logo', 'group', 'search', 'popup', 'action', 'border', 'radius', 'shadow', 'density'],
|
|
11
|
-
navigationShape: {
|
|
12
|
-
reference: 'yida-skills/skills/yida-design/references/application-theme-consistency.md#导航形状与密度的案例经验',
|
|
13
|
-
inputs: ['radius', 'normal_hover_selected_borders', 'selected_shadow', 'item_height', 'padding', 'gap', 'shell_spacing'],
|
|
14
|
-
authoring: { fast: 'design.md tokens.application-global.appearance.navigation', plan: 'visualStyle.tokens' },
|
|
15
|
-
layout: 'preserve_business_navigation_type_independently_of_theme_appearance',
|
|
16
|
-
verification: ['native_data_management', 'custom_page', 'submission', 'record_detail', 'long_labels', 'collapsed_navigation'],
|
|
17
|
-
},
|
|
18
|
-
delivery: 'one_design_document_and_application_theme_css',
|
|
19
|
-
verification: 'read_back_app_settings_and_verify_rendered_navigation_form_custom_page_and_detail',
|
|
20
|
-
},
|
|
21
|
-
nativeFormLayout: {
|
|
22
|
-
model: 'component_based_native_form_layout',
|
|
23
|
-
regions: ['top', 'left', 'main', 'right', 'between_fields'],
|
|
24
|
-
components: ['tabs', 'button_groups', 'images', 'graphics', 'status_blocks', 'dividers', 'columns', 'fields'],
|
|
25
|
-
roles: ['navigation', 'action', 'visual_focus', 'feedback', 'hierarchy', 'rhythm', 'decoration', 'data_capture'],
|
|
26
|
-
rules: ['place_components_by_role', 'preserve_existing_component_tree', 'use_divider_for_business_groups'],
|
|
27
|
-
forbidden: ['generic_filler_copy', 'random_layout_rotation'],
|
|
28
|
-
},
|
|
29
|
-
creativeOption: { alwaysAvailable: true, themeId: 'free-creative', selectionRequired: false,
|
|
30
|
-
source: 'independent_business_reasoning_not_preset_matching',
|
|
31
|
-
authoringReference: 'yida-skills/skills/yida-design/references/application-style-library.md' },
|
|
32
|
-
comparison: { candidateCount: 3, baseline: 'first_instinct', alternatives: 2, distinctDimensions: 2,
|
|
33
|
-
dimensions: ['composition', 'typography', 'surface_hierarchy', 'color_relationships', 'navigation_shape_and_density'] },
|
|
34
|
-
selection: 'refine_and_choose_a_supported_alternative_within_business_constraints',
|
|
35
|
-
quality: ['task_efficiency', 'readability_and_contrast', 'consistent_spacing_and_alignment', 'coherent_visual_identity'],
|
|
36
|
-
execution: 'one_shared_three_direction_generation_pass_for_fast_and_plan',
|
|
37
|
-
handoff: ['visualSelection.visualDirection.description', 'visualSelection.colorStrategy.usage'],
|
|
38
|
-
presentation: 'fast_selects_internally; plan_asks_user_when_no_explicit_visual_direction',
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
module.exports = { getVisualDecisionPolicy };
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Button } from 'antd';
|
|
3
|
-
|
|
4
|
-
// Page-scoped server context, not CLI credentials or a copied administrator list.
|
|
5
|
-
// The platform's app-admin scope includes super/app managers, not only MAIN.
|
|
6
|
-
function readCanvasAppAdmin(appType) {
|
|
7
|
-
try {
|
|
8
|
-
// Access pages may expose appType on pageConfig rather than g_config.
|
|
9
|
-
// Any explicit conflicting context remains unknown; never borrow parent roles.
|
|
10
|
-
const appContexts = [window.g_config?.appType, window.pageConfig?.appType]
|
|
11
|
-
.filter(value => value !== undefined && value !== null && value !== '');
|
|
12
|
-
const user = window.loginUser;
|
|
13
|
-
if (!/^APP_[A-Za-z0-9_-]+$/.test(appType || '') || !appContexts.length || appContexts.some(value => value !== appType)
|
|
14
|
-
|| typeof user?.userId !== 'string' || !user.userId.trim()) return { appType, status: 'unknown' };
|
|
15
|
-
const flag = user.isAppAdmin;
|
|
16
|
-
const status = flag === 'y' || flag === true ? 'allowed' : flag === 'n' || flag === false ? 'denied' : 'unknown';
|
|
17
|
-
return { appType, status };
|
|
18
|
-
} catch (_error) { return { appType, status: 'unknown' }; }
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function useCanvasAppAdmin(appType) {
|
|
22
|
-
const [access, setAccess] = React.useState({ appType, status: 'unknown' });
|
|
23
|
-
React.useEffect(() => {
|
|
24
|
-
const refresh = () => setAccess(readCanvasAppAdmin(appType));
|
|
25
|
-
refresh();
|
|
26
|
-
window.addEventListener('focus', refresh);
|
|
27
|
-
window.addEventListener('pageshow', refresh);
|
|
28
|
-
document.addEventListener('visibilitychange', refresh);
|
|
29
|
-
return () => {
|
|
30
|
-
window.removeEventListener('focus', refresh);
|
|
31
|
-
window.removeEventListener('pageshow', refresh);
|
|
32
|
-
document.removeEventListener('visibilitychange', refresh);
|
|
33
|
-
};
|
|
34
|
-
}, [appType]);
|
|
35
|
-
return access.appType === appType ? access.status : 'unknown';
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function buildCanvasWorkbenchEntry({ appType, workbenchFormUuid, viewUuid, params = {}, useDefaultWorkbench = false }) {
|
|
39
|
-
if (!appType || (!workbenchFormUuid && !useDefaultWorkbench)) return null;
|
|
40
|
-
if (workbenchFormUuid && [window.g_config?.formUuid, window.pageConfig?.formUuid].includes(workbenchFormUuid)) return null;
|
|
41
|
-
const query = { ...params };
|
|
42
|
-
// Do not carry the visitor page's navigation hiding/embedding settings back.
|
|
43
|
-
for (const key of ['isRenderNav', 'iframe', 'hideLeftNav', 'navConfig.layout']) delete query[key];
|
|
44
|
-
if (viewUuid && workbenchFormUuid) query.viewUuid = viewUuid;
|
|
45
|
-
return { targetType: workbenchFormUuid ? 'page' : 'app', appType, formUuid: workbenchFormUuid, params: query };
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/** Render under CanvasThemeProvider; extract canvas-admin-entry as one fragment. */
|
|
49
|
-
function CanvasAdminWorkbenchButton({ appType, workbenchFormUuid, viewUuid, params, useDefaultWorkbench = false, label = '业务工作台' }) {
|
|
50
|
-
const status = useCanvasAppAdmin(appType);
|
|
51
|
-
if (status !== 'allowed') return null;
|
|
52
|
-
const entry = buildCanvasWorkbenchEntry({ appType, workbenchFormUuid, viewUuid, params, useDefaultWorkbench });
|
|
53
|
-
if (!entry) return null;
|
|
54
|
-
let href;
|
|
55
|
-
try { href = buildCanvasPageUrl(entry, { appType }); } catch (_error) { return null; }
|
|
56
|
-
return <Button href={href} style={{ color: 'var(--color-text1-4, inherit)' }} onClick={event => {
|
|
57
|
-
if (readCanvasAppAdmin(appType).status !== 'allowed') { event.preventDefault(); return; }
|
|
58
|
-
if (event.button !== 0 || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) return;
|
|
59
|
-
event.preventDefault();
|
|
60
|
-
navigateCanvasPage(entry, { appType });
|
|
61
|
-
}}>{label}</Button>;
|
|
62
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
// Merge this fragment into the Canvas page. Supply IDs from resource readback.
|
|
2
|
-
// Local tabs use state/hash and do not call this cross-page helper.
|
|
3
|
-
function buildCanvasPageUrl(entry, { appType, platformOrigin } = {}) {
|
|
4
|
-
const type = entry.targetType;
|
|
5
|
-
if (type === 'url') {
|
|
6
|
-
const external = new URL(entry.url);
|
|
7
|
-
if (!['https:', 'http:'].includes(external.protocol)) throw new Error('Expected an HTTP(S) URL');
|
|
8
|
-
return external.href;
|
|
9
|
-
}
|
|
10
|
-
const app = entry.appType || appType;
|
|
11
|
-
if (!/^APP_[A-Za-z0-9_-]+$/.test(app || '')) throw new Error('Missing verified appType');
|
|
12
|
-
const routes = { app: 'workbench', page: 'workbench', custom: 'custom', submission: 'submission', detail: 'formDetail' };
|
|
13
|
-
if (!Object.prototype.hasOwnProperty.call(routes, type)) throw new Error('Unknown page target type');
|
|
14
|
-
const id = type === 'page' ? entry.navUuid || entry.formUuid : entry.formUuid;
|
|
15
|
-
if (type !== 'app' && !/^[A-Za-z0-9_-]+$/.test(id || '')) throw new Error('Missing verified page ID');
|
|
16
|
-
// Normal pages use their own origin. Opaque or non-platform embeddings must
|
|
17
|
-
// supply the verified platform origin; never guess a tenant or read window.top.
|
|
18
|
-
const origin = new URL(platformOrigin || window.location.origin);
|
|
19
|
-
if (!['https:', 'http:'].includes(origin.protocol) || origin.username || origin.password) throw new Error('Invalid platform origin');
|
|
20
|
-
const url = new URL('/' + app + '/' + routes[type] + (type === 'app' ? '' : '/' + id), origin.origin);
|
|
21
|
-
Object.entries(entry.params || {}).forEach(([key, val]) => {
|
|
22
|
-
if (val !== undefined && val !== null && val !== '') url.searchParams.set(key, String(val));
|
|
23
|
-
});
|
|
24
|
-
if (type === 'submission' || type === 'detail') url.searchParams.set('isRenderNav', 'false');
|
|
25
|
-
if (type === 'detail') {
|
|
26
|
-
if (typeof entry.formInstId !== 'string' || !entry.formInstId.trim()) throw new Error('Missing formInstId');
|
|
27
|
-
url.searchParams.set('formInstId', entry.formInstId);
|
|
28
|
-
url.searchParams.set('navConfig.layout', '1180');
|
|
29
|
-
}
|
|
30
|
-
if (entry.hash) url.hash = entry.hash;
|
|
31
|
-
return url.href;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function navigateCanvasPage(entry, context = {}) {
|
|
35
|
-
if (entry.targetType === 'local') {
|
|
36
|
-
if (!entry.viewKey || typeof context.selectView !== 'function') throw new Error('Missing local view handler');
|
|
37
|
-
context.selectView(entry.viewKey);
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
if (entry.targetType === 'submission' || entry.targetType === 'detail') {
|
|
41
|
-
// Validate before opening; the standard container owns PC/mobile behavior.
|
|
42
|
-
buildCanvasPageUrl(entry, context);
|
|
43
|
-
if (typeof context.openForm !== 'function') throw new Error('Connect useYidaFormOpen first');
|
|
44
|
-
context.openForm({ ...entry, type: entry.targetType, appType: entry.appType || context.appType });
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
const href = buildCanvasPageUrl(entry, context);
|
|
48
|
-
const utils = context.utils || window.__OPENYIDA_UTILS__;
|
|
49
|
-
if (entry.openMode === 'new-tab' || entry.targetType === 'url') {
|
|
50
|
-
if (typeof utils?.openPage === 'function') return utils.openPage({ url: href });
|
|
51
|
-
window.open(href, '_blank', 'noopener,noreferrer');
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
if (typeof utils?.router?.push === 'function') return utils.router.push(href, {}, false, true);
|
|
55
|
-
window.location.assign(href);
|
|
56
|
-
}
|