@fses/workbench-app 0.1.3 → 0.2.1
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/WORKBENCH-CLOSURE.json +80 -0
- package/dist/{Workspace-CvJghuPy.js → Workspace-DMye5DU8.js} +11458 -11325
- package/dist/canvas/api/index.d.ts +7 -0
- package/dist/canvas/api/index.js +4 -0
- package/dist/canvasFacade-B0oy__da.js +1932 -0
- package/dist/cardFactory-CoDF-zsR.js +1392 -0
- package/dist/extensions/index.d.ts +2 -0
- package/dist/extensions/index.js +8 -0
- package/dist/fses-workbench-app.js +89 -86
- package/dist/index-DbH6tMQy.js +837 -0
- package/dist/internal/personal-workbench/lib/workbenchChatReplyBridge.d.ts +24 -0
- package/dist/runtime/index.js +1 -1
- package/dist/style.css +1 -1
- package/dist/{useWorkbenchRuntime-Pekhufen.js → useWorkbenchRuntime-XpOzwm56.js} +8752 -11980
- package/dist/workbenchCustomComponentRegistry-6GHzavdM.js +267 -0
- package/node_modules/@byteluck/agentic-protocol/LICENSE +9 -0
- package/node_modules/@byteluck/agentic-protocol/README.md +74 -0
- package/node_modules/@byteluck/agentic-protocol/dist/index.d.ts +1623 -0
- package/node_modules/@byteluck/agentic-protocol/dist/index.mjs +3380 -0
- package/node_modules/@byteluck/agentic-protocol/package.json +37 -0
- package/node_modules/@byteluck/workbench-skill-contracts/LICENSE +9 -0
- package/node_modules/@byteluck/workbench-skill-contracts/dist/index.d.ts +234 -0
- package/node_modules/@byteluck/workbench-skill-contracts/dist/index.mjs +394 -0
- package/node_modules/@byteluck/workbench-skill-contracts/package.json +37 -0
- package/node_modules/@fses/ai-chat/LICENSE +9 -0
- package/node_modules/@fses/ai-chat/README.md +320 -0
- package/node_modules/@fses/ai-chat/dist/chart-card/data.d.ts +12 -0
- package/node_modules/@fses/ai-chat/dist/chart-card/from-markdown.d.ts +11 -0
- package/node_modules/@fses/ai-chat/dist/chart-card/from-tool.d.ts +8 -0
- package/node_modules/@fses/ai-chat/dist/chart-card/options.d.ts +4 -0
- package/node_modules/@fses/ai-chat/dist/chart-card/trace.d.ts +19 -0
- package/node_modules/@fses/ai-chat/dist/chart-card/types.d.ts +133 -0
- package/node_modules/@fses/ai-chat/dist/components/CardRecommendationDeferredDraft.vue.d.ts +13 -0
- package/node_modules/@fses/ai-chat/dist/components/CardRecommendationDraft.vue.d.ts +18 -0
- package/node_modules/@fses/ai-chat/dist/components/ChartCardRenderer.vue.d.ts +11 -0
- package/node_modules/@fses/ai-chat/dist/components/ChatMessageItem.vue.d.ts +76 -0
- package/node_modules/@fses/ai-chat/dist/components/ChatMessageList.vue.d.ts +79 -0
- package/node_modules/@fses/ai-chat/dist/components/ChatSender.vue.d.ts +98 -0
- package/node_modules/@fses/ai-chat/dist/components/CollapsedToolActivity.vue.d.ts +9 -0
- package/node_modules/@fses/ai-chat/dist/components/ContextUsageRing.vue.d.ts +12 -0
- package/node_modules/@fses/ai-chat/dist/components/EChartsView.vue.d.ts +6 -0
- package/node_modules/@fses/ai-chat/dist/components/FsesAiChat.vue.d.ts +306 -0
- package/node_modules/@fses/ai-chat/dist/components/PlanDraftCard.vue.d.ts +19 -0
- package/node_modules/@fses/ai-chat/dist/components/ShellExecPanel.vue.d.ts +6 -0
- package/node_modules/@fses/ai-chat/dist/components/TaskTodoPlanBar.vue.d.ts +6 -0
- package/node_modules/@fses/ai-chat/dist/components/ThinkingShimmer.vue.d.ts +6 -0
- package/node_modules/@fses/ai-chat/dist/composables/context-usage.d.ts +11 -0
- package/node_modules/@fses/ai-chat/dist/composables/types.d.ts +465 -0
- package/node_modules/@fses/ai-chat/dist/composables/useChat.d.ts +2 -0
- package/node_modules/@fses/ai-chat/dist/composables/useSystemEChartsIcon.d.ts +11 -0
- package/node_modules/@fses/ai-chat/dist/fses-ai-chat.js +11408 -0
- package/node_modules/@fses/ai-chat/dist/fses-ai-chat.umd.cjs +25 -0
- package/node_modules/@fses/ai-chat/dist/index.d.ts +17 -0
- package/node_modules/@fses/ai-chat/dist/plugin.d.ts +8 -0
- package/node_modules/@fses/ai-chat/dist/style.css +1 -0
- package/node_modules/@fses/ai-chat/dist/utils/assistant-markdown.d.ts +11 -0
- package/node_modules/@fses/ai-chat/dist/utils/attachment-upload.d.ts +22 -0
- package/node_modules/@fses/ai-chat/dist/utils/card-recommendation-config-summary.d.ts +86 -0
- package/node_modules/@fses/ai-chat/dist/utils/card-recommendation-field-label.d.ts +24 -0
- package/node_modules/@fses/ai-chat/dist/utils/card-recommendation-source.d.ts +18 -0
- package/node_modules/@fses/ai-chat/dist/utils/card-recommendation-title-source.d.ts +12 -0
- package/node_modules/@fses/ai-chat/dist/utils/chart-card-visibility.d.ts +24 -0
- package/node_modules/@fses/ai-chat/dist/utils/derived-process-labels.d.ts +13 -0
- package/node_modules/@fses/ai-chat/dist/utils/echarts-recommendation-icon.d.ts +36 -0
- package/node_modules/@fses/ai-chat/dist/utils/group-messages.d.ts +30 -0
- package/node_modules/@fses/ai-chat/dist/utils/status-activity.d.ts +48 -0
- package/node_modules/@fses/ai-chat/dist/utils/system-echarts-template-icons.generated.d.ts +305 -0
- package/node_modules/@fses/ai-chat/dist/utils/system-echarts-template.d.ts +20 -0
- package/node_modules/@fses/ai-chat/dist/utils/task-todo-plan.d.ts +40 -0
- package/node_modules/@fses/ai-chat/dist/utils/workbench-echarts-theme.d.ts +35 -0
- package/node_modules/@fses/ai-chat/package.json +81 -0
- package/node_modules/@fses/workbench-card/LICENSE +9 -0
- package/node_modules/@fses/workbench-card/README.md +81 -0
- package/node_modules/@fses/workbench-card/dist/chart/index.d.ts +8 -0
- package/node_modules/@fses/workbench-card/dist/fses-workbench-card-echarts-protocol.js +2230 -0
- package/node_modules/@fses/workbench-card/dist/fses-workbench-card-renderers.js +33731 -0
- package/node_modules/@fses/workbench-card/dist/fses-workbench-card.js +21238 -0
- package/node_modules/@fses/workbench-card/dist/fses-workbench-card.umd.cjs +1 -0
- package/node_modules/@fses/workbench-card/dist/index.d.ts +11 -0
- package/node_modules/@fses/workbench-card/dist/registry/cardRegistry.d.ts +50 -0
- package/node_modules/@fses/workbench-card/dist/registry/compositeCardPatterns.d.ts +39 -0
- package/node_modules/@fses/workbench-card/dist/registry/echartsTemplateCategories.d.ts +20 -0
- package/node_modules/@fses/workbench-card/dist/registry/echartsTemplateRegistry.d.ts +1158 -0
- package/node_modules/@fses/workbench-card/dist/registry/echartsTemplateRegistry.generated.d.ts +1141 -0
- package/node_modules/@fses/workbench-card/dist/registry/echartsTemplateTypes.d.ts +76 -0
- package/node_modules/@fses/workbench-card/dist/registry/index.d.ts +10 -0
- package/node_modules/@fses/workbench-card/dist/renderers/WorkbenchBlockRenderer.vue.d.ts +55 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/ChartRegistry.vue.d.ts +22 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/EChartsProtocolRenderer.vue.d.ts +34 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/chartRendererRegistry.d.ts +219 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/chartResponsiveLayout.d.ts +47 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/dynamicEchartOption.d.ts +30 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/echarts-protocol/adapter.d.ts +73 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/echarts-protocol/converters/composite.converter.d.ts +11 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/echarts-protocol/converters/configOnly.converter.d.ts +11 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/echarts-protocol/converters/geo.converter.d.ts +10 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/echarts-protocol/converters/graphic.converter.d.ts +10 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/echarts-protocol/converters/layout.converter.d.ts +11 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/echarts-protocol/converters/network.converter.d.ts +10 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/echarts-protocol/converters/scene3D.converter.d.ts +11 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/echarts-protocol/converters/series.converter.d.ts +10 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/echarts-protocol/converters/table.converter.d.ts +10 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/echarts-protocol/converters/timeline.converter.d.ts +11 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/echarts-protocol/converters/transition.converter.d.ts +11 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/echarts-protocol/converters/tree.converter.d.ts +10 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/echarts-protocol/converters/tuple.converter.d.ts +10 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/echarts-protocol/index.d.ts +9 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/echarts-protocol/merger.d.ts +16 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/echarts-protocol/types.d.ts +447 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/echartsRuntimeInteractions.d.ts +30 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/echartsTitle.d.ts +13 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/echartsTooltipPortal.d.ts +12 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/types.d.ts +47 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/useEchart.d.ts +29 -0
- package/node_modules/@fses/workbench-card/dist/renderers/chart/workbenchChartTheme.d.ts +36 -0
- package/node_modules/@fses/workbench-card/dist/renderers/custom-canvas/canvasLayoutBindings.d.ts +86 -0
- package/node_modules/@fses/workbench-card/dist/renderers/hostBridge.d.ts +61 -0
- package/node_modules/@fses/workbench-card/dist/renderers/index.d.ts +17 -0
- package/node_modules/@fses/workbench-card/dist/renderers/native/nativeBindings.d.ts +145 -0
- package/node_modules/@fses/workbench-card/dist/renderers/nested/nestedBlockBindings.d.ts +107 -0
- package/node_modules/@fses/workbench-card/dist/renderers/quickLinkDisplay.d.ts +24 -0
- package/node_modules/@fses/workbench-card/dist/renderers/reference-composite/referenceCompositeBindings.d.ts +171 -0
- package/node_modules/@fses/workbench-card/dist/renderers/reference-composite/referenceRiskAndStrategyBindings.d.ts +91 -0
- package/node_modules/@fses/workbench-card/dist/renderers/resizableTable.d.ts +51 -0
- package/node_modules/@fses/workbench-card/dist/renderers/style.css +1 -0
- package/node_modules/@fses/workbench-card/dist/renderers/tableDisplay.d.ts +25 -0
- package/node_modules/@fses/workbench-card/dist/renderers/useWorkbenchBlockRendererBindings.d.ts +580 -0
- package/node_modules/@fses/workbench-card/dist/shell/workbenchVisualShell.d.ts +48 -0
- package/node_modules/@fses/workbench-card/dist/style.css +1 -0
- package/node_modules/@fses/workbench-card/dist/types/block.d.ts +2002 -0
- package/node_modules/@fses/workbench-card/dist/types/canvas.d.ts +25 -0
- package/node_modules/@fses/workbench-card/dist/types/echartsProtocol.d.ts +445 -0
- package/node_modules/@fses/workbench-card/dist/types/index.d.ts +10 -0
- package/node_modules/@fses/workbench-card/dist/types/registry.d.ts +7 -0
- package/node_modules/@fses/workbench-card/dist/types/runtime.d.ts +34 -0
- package/node_modules/@fses/workbench-card/package.json +82 -0
- package/node_modules/@fses/workbench-card/src/chart/index.ts +8 -0
- package/node_modules/@fses/workbench-card/src/index.ts +13 -0
- package/node_modules/@fses/workbench-card/src/registry/cardRegistry.ts +476 -0
- package/node_modules/@fses/workbench-card/src/registry/compositeCardPatterns.ts +206 -0
- package/node_modules/@fses/workbench-card/src/registry/echartsTemplateCategories.ts +74 -0
- package/node_modules/@fses/workbench-card/src/registry/echartsTemplateRegistry.generated.ts +19951 -0
- package/node_modules/@fses/workbench-card/src/registry/echartsTemplateRegistry.ts +32 -0
- package/node_modules/@fses/workbench-card/src/registry/echartsTemplateTypes.ts +83 -0
- package/node_modules/@fses/workbench-card/src/registry/index.ts +10 -0
- package/node_modules/@fses/workbench-card/src/renderers/WorkbenchBlockRenderer.vue +2728 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/ChartRegistry.vue +221 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/EChartsProtocolRenderer.vue +304 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/chartRendererRegistry.ts +311 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/chartResponsiveLayout.ts +172 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/dynamicEchartOption.ts +127 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/echarts-protocol/adapter.ts +1349 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/echarts-protocol/converters/composite.converter.ts +71 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/echarts-protocol/converters/configOnly.converter.ts +45 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/echarts-protocol/converters/geo.converter.ts +97 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/echarts-protocol/converters/graphic.converter.ts +59 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/echarts-protocol/converters/layout.converter.ts +53 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/echarts-protocol/converters/network.converter.ts +82 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/echarts-protocol/converters/scene3D.converter.ts +73 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/echarts-protocol/converters/series.converter.ts +795 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/echarts-protocol/converters/table.converter.ts +195 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/echarts-protocol/converters/timeline.converter.ts +62 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/echarts-protocol/converters/transition.converter.ts +58 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/echarts-protocol/converters/tree.converter.ts +75 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/echarts-protocol/converters/tuple.converter.ts +112 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/echarts-protocol/index.ts +10 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/echarts-protocol/merger.ts +109 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/echarts-protocol/types.ts +515 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/echartsRuntimeInteractions.ts +450 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/echartsTitle.ts +94 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/echartsTooltipPortal.ts +140 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/types.ts +53 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/useEchart.ts +1820 -0
- package/node_modules/@fses/workbench-card/src/renderers/chart/workbenchChartTheme.ts +240 -0
- package/node_modules/@fses/workbench-card/src/renderers/custom-canvas/canvasLayoutBindings.ts +660 -0
- package/node_modules/@fses/workbench-card/src/renderers/hostBridge.ts +74 -0
- package/node_modules/@fses/workbench-card/src/renderers/index.ts +25 -0
- package/node_modules/@fses/workbench-card/src/renderers/native/nativeBindings.ts +1081 -0
- package/node_modules/@fses/workbench-card/src/renderers/nested/nestedBlockBindings.ts +1349 -0
- package/node_modules/@fses/workbench-card/src/renderers/quickLinkDisplay.ts +53 -0
- package/node_modules/@fses/workbench-card/src/renderers/reference-composite/referenceCompositeBindings.ts +3205 -0
- package/node_modules/@fses/workbench-card/src/renderers/reference-composite/referenceRiskAndStrategyBindings.ts +1004 -0
- package/node_modules/@fses/workbench-card/src/renderers/resizableTable.ts +136 -0
- package/node_modules/@fses/workbench-card/src/renderers/tableDisplay.ts +140 -0
- package/node_modules/@fses/workbench-card/src/renderers/useWorkbenchBlockRendererBindings.ts +3192 -0
- package/node_modules/@fses/workbench-card/src/shell/workbenchVisualShell.ts +228 -0
- package/node_modules/@fses/workbench-card/src/styles/workbench-card.css +343 -0
- package/node_modules/@fses/workbench-card/src/types/block.ts +2487 -0
- package/node_modules/@fses/workbench-card/src/types/canvas.ts +30 -0
- package/node_modules/@fses/workbench-card/src/types/echartsProtocol.ts +513 -0
- package/node_modules/@fses/workbench-card/src/types/index.ts +10 -0
- package/node_modules/@fses/workbench-card/src/types/registry.ts +17 -0
- package/node_modules/@fses/workbench-card/src/types/runtime.ts +31 -0
- package/node_modules/dompurify/LICENSE +568 -0
- package/node_modules/dompurify/README.md +523 -0
- package/node_modules/dompurify/dist/purify.cjs.d.ts +451 -0
- package/node_modules/dompurify/dist/purify.cjs.js +1472 -0
- package/node_modules/dompurify/dist/purify.cjs.js.map +1 -0
- package/node_modules/dompurify/dist/purify.es.d.mts +448 -0
- package/node_modules/dompurify/dist/purify.es.mjs +1470 -0
- package/node_modules/dompurify/dist/purify.es.mjs.map +1 -0
- package/node_modules/dompurify/dist/purify.js +1478 -0
- package/node_modules/dompurify/dist/purify.js.map +1 -0
- package/node_modules/dompurify/dist/purify.min.js +3 -0
- package/node_modules/dompurify/dist/purify.min.js.map +1 -0
- package/node_modules/dompurify/package.json +168 -0
- package/node_modules/zod/LICENSE +21 -0
- package/node_modules/zod/README.md +208 -0
- package/node_modules/zod/index.cjs +33 -0
- package/node_modules/zod/index.d.cts +4 -0
- package/node_modules/zod/index.d.ts +4 -0
- package/node_modules/zod/index.js +4 -0
- package/node_modules/zod/package.json +118 -0
- package/node_modules/zod/src/index.ts +4 -0
- package/node_modules/zod/src/v3/ZodError.ts +330 -0
- package/node_modules/zod/src/v3/benchmarks/datetime.ts +58 -0
- package/node_modules/zod/src/v3/benchmarks/discriminatedUnion.ts +80 -0
- package/node_modules/zod/src/v3/benchmarks/index.ts +59 -0
- package/node_modules/zod/src/v3/benchmarks/ipv4.ts +57 -0
- package/node_modules/zod/src/v3/benchmarks/object.ts +69 -0
- package/node_modules/zod/src/v3/benchmarks/primitives.ts +162 -0
- package/node_modules/zod/src/v3/benchmarks/realworld.ts +63 -0
- package/node_modules/zod/src/v3/benchmarks/string.ts +55 -0
- package/node_modules/zod/src/v3/benchmarks/union.ts +80 -0
- package/node_modules/zod/src/v3/errors.ts +13 -0
- package/node_modules/zod/src/v3/external.ts +6 -0
- package/node_modules/zod/src/v3/helpers/enumUtil.ts +17 -0
- package/node_modules/zod/src/v3/helpers/errorUtil.ts +8 -0
- package/node_modules/zod/src/v3/helpers/parseUtil.ts +176 -0
- package/node_modules/zod/src/v3/helpers/partialUtil.ts +34 -0
- package/node_modules/zod/src/v3/helpers/typeAliases.ts +2 -0
- package/node_modules/zod/src/v3/helpers/util.ts +224 -0
- package/node_modules/zod/src/v3/index.ts +4 -0
- package/node_modules/zod/src/v3/locales/en.ts +124 -0
- package/node_modules/zod/src/v3/standard-schema.ts +113 -0
- package/node_modules/zod/src/v3/tests/Mocker.ts +54 -0
- package/node_modules/zod/src/v3/tests/all-errors.test.ts +157 -0
- package/node_modules/zod/src/v3/tests/anyunknown.test.ts +28 -0
- package/node_modules/zod/src/v3/tests/array.test.ts +71 -0
- package/node_modules/zod/src/v3/tests/async-parsing.test.ts +388 -0
- package/node_modules/zod/src/v3/tests/async-refinements.test.ts +46 -0
- package/node_modules/zod/src/v3/tests/base.test.ts +29 -0
- package/node_modules/zod/src/v3/tests/bigint.test.ts +55 -0
- package/node_modules/zod/src/v3/tests/branded.test.ts +53 -0
- package/node_modules/zod/src/v3/tests/catch.test.ts +220 -0
- package/node_modules/zod/src/v3/tests/coerce.test.ts +133 -0
- package/node_modules/zod/src/v3/tests/complex.test.ts +56 -0
- package/node_modules/zod/src/v3/tests/custom.test.ts +31 -0
- package/node_modules/zod/src/v3/tests/date.test.ts +32 -0
- package/node_modules/zod/src/v3/tests/deepmasking.test.ts +186 -0
- package/node_modules/zod/src/v3/tests/default.test.ts +112 -0
- package/node_modules/zod/src/v3/tests/description.test.ts +33 -0
- package/node_modules/zod/src/v3/tests/discriminated-unions.test.ts +315 -0
- package/node_modules/zod/src/v3/tests/enum.test.ts +80 -0
- package/node_modules/zod/src/v3/tests/error.test.ts +551 -0
- package/node_modules/zod/src/v3/tests/firstparty.test.ts +87 -0
- package/node_modules/zod/src/v3/tests/firstpartyschematypes.test.ts +21 -0
- package/node_modules/zod/src/v3/tests/function.test.ts +257 -0
- package/node_modules/zod/src/v3/tests/generics.test.ts +48 -0
- package/node_modules/zod/src/v3/tests/instanceof.test.ts +37 -0
- package/node_modules/zod/src/v3/tests/intersection.test.ts +110 -0
- package/node_modules/zod/src/v3/tests/language-server.source.ts +76 -0
- package/node_modules/zod/src/v3/tests/language-server.test.ts +207 -0
- package/node_modules/zod/src/v3/tests/literal.test.ts +36 -0
- package/node_modules/zod/src/v3/tests/map.test.ts +110 -0
- package/node_modules/zod/src/v3/tests/masking.test.ts +4 -0
- package/node_modules/zod/src/v3/tests/mocker.test.ts +19 -0
- package/node_modules/zod/src/v3/tests/nan.test.ts +21 -0
- package/node_modules/zod/src/v3/tests/nativeEnum.test.ts +87 -0
- package/node_modules/zod/src/v3/tests/nullable.test.ts +42 -0
- package/node_modules/zod/src/v3/tests/number.test.ts +176 -0
- package/node_modules/zod/src/v3/tests/object-augmentation.test.ts +29 -0
- package/node_modules/zod/src/v3/tests/object-in-es5-env.test.ts +29 -0
- package/node_modules/zod/src/v3/tests/object.test.ts +434 -0
- package/node_modules/zod/src/v3/tests/optional.test.ts +42 -0
- package/node_modules/zod/src/v3/tests/parseUtil.test.ts +23 -0
- package/node_modules/zod/src/v3/tests/parser.test.ts +41 -0
- package/node_modules/zod/src/v3/tests/partials.test.ts +243 -0
- package/node_modules/zod/src/v3/tests/pickomit.test.ts +111 -0
- package/node_modules/zod/src/v3/tests/pipeline.test.ts +29 -0
- package/node_modules/zod/src/v3/tests/preprocess.test.ts +186 -0
- package/node_modules/zod/src/v3/tests/primitive.test.ts +440 -0
- package/node_modules/zod/src/v3/tests/promise.test.ts +90 -0
- package/node_modules/zod/src/v3/tests/readonly.test.ts +194 -0
- package/node_modules/zod/src/v3/tests/record.test.ts +171 -0
- package/node_modules/zod/src/v3/tests/recursive.test.ts +197 -0
- package/node_modules/zod/src/v3/tests/refine.test.ts +313 -0
- package/node_modules/zod/src/v3/tests/safeparse.test.ts +27 -0
- package/node_modules/zod/src/v3/tests/set.test.ts +142 -0
- package/node_modules/zod/src/v3/tests/standard-schema.test.ts +83 -0
- package/node_modules/zod/src/v3/tests/string.test.ts +916 -0
- package/node_modules/zod/src/v3/tests/transformer.test.ts +233 -0
- package/node_modules/zod/src/v3/tests/tuple.test.ts +90 -0
- package/node_modules/zod/src/v3/tests/unions.test.ts +57 -0
- package/node_modules/zod/src/v3/tests/validations.test.ts +133 -0
- package/node_modules/zod/src/v3/tests/void.test.ts +15 -0
- package/node_modules/zod/src/v3/types.ts +5136 -0
- package/node_modules/zod/src/v4/classic/checks.ts +30 -0
- package/node_modules/zod/src/v4/classic/coerce.ts +27 -0
- package/node_modules/zod/src/v4/classic/compat.ts +66 -0
- package/node_modules/zod/src/v4/classic/errors.ts +75 -0
- package/node_modules/zod/src/v4/classic/external.ts +50 -0
- package/node_modules/zod/src/v4/classic/index.ts +5 -0
- package/node_modules/zod/src/v4/classic/iso.ts +90 -0
- package/node_modules/zod/src/v4/classic/parse.ts +33 -0
- package/node_modules/zod/src/v4/classic/schemas.ts +2054 -0
- package/node_modules/zod/src/v4/classic/tests/anyunknown.test.ts +26 -0
- package/node_modules/zod/src/v4/classic/tests/array.test.ts +264 -0
- package/node_modules/zod/src/v4/classic/tests/assignability.test.ts +210 -0
- package/node_modules/zod/src/v4/classic/tests/async-parsing.test.ts +381 -0
- package/node_modules/zod/src/v4/classic/tests/async-refinements.test.ts +68 -0
- package/node_modules/zod/src/v4/classic/tests/base.test.ts +7 -0
- package/node_modules/zod/src/v4/classic/tests/bigint.test.ts +54 -0
- package/node_modules/zod/src/v4/classic/tests/brand.test.ts +63 -0
- package/node_modules/zod/src/v4/classic/tests/catch.test.ts +252 -0
- package/node_modules/zod/src/v4/classic/tests/coalesce.test.ts +20 -0
- package/node_modules/zod/src/v4/classic/tests/coerce.test.ts +160 -0
- package/node_modules/zod/src/v4/classic/tests/continuability.test.ts +352 -0
- package/node_modules/zod/src/v4/classic/tests/custom.test.ts +40 -0
- package/node_modules/zod/src/v4/classic/tests/date.test.ts +31 -0
- package/node_modules/zod/src/v4/classic/tests/datetime.test.ts +296 -0
- package/node_modules/zod/src/v4/classic/tests/default.test.ts +313 -0
- package/node_modules/zod/src/v4/classic/tests/description.test.ts +32 -0
- package/node_modules/zod/src/v4/classic/tests/discriminated-unions.test.ts +619 -0
- package/node_modules/zod/src/v4/classic/tests/enum.test.ts +285 -0
- package/node_modules/zod/src/v4/classic/tests/error-utils.test.ts +527 -0
- package/node_modules/zod/src/v4/classic/tests/error.test.ts +711 -0
- package/node_modules/zod/src/v4/classic/tests/file.test.ts +91 -0
- package/node_modules/zod/src/v4/classic/tests/firstparty.test.ts +175 -0
- package/node_modules/zod/src/v4/classic/tests/function.test.ts +268 -0
- package/node_modules/zod/src/v4/classic/tests/generics.test.ts +72 -0
- package/node_modules/zod/src/v4/classic/tests/index.test.ts +829 -0
- package/node_modules/zod/src/v4/classic/tests/instanceof.test.ts +34 -0
- package/node_modules/zod/src/v4/classic/tests/intersection.test.ts +171 -0
- package/node_modules/zod/src/v4/classic/tests/json.test.ts +108 -0
- package/node_modules/zod/src/v4/classic/tests/lazy.test.ts +227 -0
- package/node_modules/zod/src/v4/classic/tests/literal.test.ts +92 -0
- package/node_modules/zod/src/v4/classic/tests/map.test.ts +196 -0
- package/node_modules/zod/src/v4/classic/tests/nan.test.ts +21 -0
- package/node_modules/zod/src/v4/classic/tests/nested-refine.test.ts +168 -0
- package/node_modules/zod/src/v4/classic/tests/nonoptional.test.ts +86 -0
- package/node_modules/zod/src/v4/classic/tests/nullable.test.ts +22 -0
- package/node_modules/zod/src/v4/classic/tests/number.test.ts +247 -0
- package/node_modules/zod/src/v4/classic/tests/object.test.ts +563 -0
- package/node_modules/zod/src/v4/classic/tests/optional.test.ts +123 -0
- package/node_modules/zod/src/v4/classic/tests/partial.test.ts +147 -0
- package/node_modules/zod/src/v4/classic/tests/pickomit.test.ts +127 -0
- package/node_modules/zod/src/v4/classic/tests/pipe.test.ts +81 -0
- package/node_modules/zod/src/v4/classic/tests/prefault.test.ts +37 -0
- package/node_modules/zod/src/v4/classic/tests/preprocess.test.ts +298 -0
- package/node_modules/zod/src/v4/classic/tests/primitive.test.ts +175 -0
- package/node_modules/zod/src/v4/classic/tests/promise.test.ts +81 -0
- package/node_modules/zod/src/v4/classic/tests/prototypes.test.ts +23 -0
- package/node_modules/zod/src/v4/classic/tests/readonly.test.ts +252 -0
- package/node_modules/zod/src/v4/classic/tests/record.test.ts +342 -0
- package/node_modules/zod/src/v4/classic/tests/recursive-types.test.ts +356 -0
- package/node_modules/zod/src/v4/classic/tests/refine.test.ts +532 -0
- package/node_modules/zod/src/v4/classic/tests/registries.test.ts +204 -0
- package/node_modules/zod/src/v4/classic/tests/set.test.ts +179 -0
- package/node_modules/zod/src/v4/classic/tests/standard-schema.test.ts +57 -0
- package/node_modules/zod/src/v4/classic/tests/string-formats.test.ts +109 -0
- package/node_modules/zod/src/v4/classic/tests/string.test.ts +881 -0
- package/node_modules/zod/src/v4/classic/tests/stringbool.test.ts +66 -0
- package/node_modules/zod/src/v4/classic/tests/template-literal.test.ts +758 -0
- package/node_modules/zod/src/v4/classic/tests/to-json-schema.test.ts +2314 -0
- package/node_modules/zod/src/v4/classic/tests/transform.test.ts +250 -0
- package/node_modules/zod/src/v4/classic/tests/tuple.test.ts +163 -0
- package/node_modules/zod/src/v4/classic/tests/union.test.ts +94 -0
- package/node_modules/zod/src/v4/classic/tests/validations.test.ts +283 -0
- package/node_modules/zod/src/v4/classic/tests/void.test.ts +12 -0
- package/node_modules/zod/src/v4/core/api.ts +1594 -0
- package/node_modules/zod/src/v4/core/checks.ts +1283 -0
- package/node_modules/zod/src/v4/core/config.ts +15 -0
- package/node_modules/zod/src/v4/core/core.ts +134 -0
- package/node_modules/zod/src/v4/core/doc.ts +44 -0
- package/node_modules/zod/src/v4/core/errors.ts +424 -0
- package/node_modules/zod/src/v4/core/function.ts +176 -0
- package/node_modules/zod/src/v4/core/index.ts +15 -0
- package/node_modules/zod/src/v4/core/json-schema.ts +143 -0
- package/node_modules/zod/src/v4/core/parse.ts +94 -0
- package/node_modules/zod/src/v4/core/regexes.ts +135 -0
- package/node_modules/zod/src/v4/core/registries.ts +96 -0
- package/node_modules/zod/src/v4/core/schemas.ts +3842 -0
- package/node_modules/zod/src/v4/core/standard-schema.ts +64 -0
- package/node_modules/zod/src/v4/core/tests/index.test.ts +46 -0
- package/node_modules/zod/src/v4/core/tests/locales/be.test.ts +124 -0
- package/node_modules/zod/src/v4/core/tests/locales/en.test.ts +22 -0
- package/node_modules/zod/src/v4/core/tests/locales/ru.test.ts +128 -0
- package/node_modules/zod/src/v4/core/tests/locales/tr.test.ts +69 -0
- package/node_modules/zod/src/v4/core/to-json-schema.ts +977 -0
- package/node_modules/zod/src/v4/core/util.ts +775 -0
- package/node_modules/zod/src/v4/core/versions.ts +5 -0
- package/node_modules/zod/src/v4/core/zsf.ts +323 -0
- package/node_modules/zod/src/v4/index.ts +4 -0
- package/node_modules/zod/src/v4/locales/ar.ts +125 -0
- package/node_modules/zod/src/v4/locales/az.ts +121 -0
- package/node_modules/zod/src/v4/locales/be.ts +184 -0
- package/node_modules/zod/src/v4/locales/ca.ts +127 -0
- package/node_modules/zod/src/v4/locales/cs.ts +142 -0
- package/node_modules/zod/src/v4/locales/de.ts +124 -0
- package/node_modules/zod/src/v4/locales/en.ts +127 -0
- package/node_modules/zod/src/v4/locales/eo.ts +125 -0
- package/node_modules/zod/src/v4/locales/es.ts +125 -0
- package/node_modules/zod/src/v4/locales/fa.ts +134 -0
- package/node_modules/zod/src/v4/locales/fi.ts +131 -0
- package/node_modules/zod/src/v4/locales/fr-CA.ts +126 -0
- package/node_modules/zod/src/v4/locales/fr.ts +124 -0
- package/node_modules/zod/src/v4/locales/he.ts +125 -0
- package/node_modules/zod/src/v4/locales/hu.ts +126 -0
- package/node_modules/zod/src/v4/locales/id.ts +125 -0
- package/node_modules/zod/src/v4/locales/index.ts +39 -0
- package/node_modules/zod/src/v4/locales/it.ts +125 -0
- package/node_modules/zod/src/v4/locales/ja.ts +122 -0
- package/node_modules/zod/src/v4/locales/kh.ts +126 -0
- package/node_modules/zod/src/v4/locales/ko.ts +131 -0
- package/node_modules/zod/src/v4/locales/mk.ts +127 -0
- package/node_modules/zod/src/v4/locales/ms.ts +124 -0
- package/node_modules/zod/src/v4/locales/nl.ts +126 -0
- package/node_modules/zod/src/v4/locales/no.ts +124 -0
- package/node_modules/zod/src/v4/locales/ota.ts +125 -0
- package/node_modules/zod/src/v4/locales/pl.ts +126 -0
- package/node_modules/zod/src/v4/locales/ps.ts +133 -0
- package/node_modules/zod/src/v4/locales/pt.ts +123 -0
- package/node_modules/zod/src/v4/locales/ru.ts +184 -0
- package/node_modules/zod/src/v4/locales/sl.ts +126 -0
- package/node_modules/zod/src/v4/locales/sv.ts +127 -0
- package/node_modules/zod/src/v4/locales/ta.ts +125 -0
- package/node_modules/zod/src/v4/locales/th.ts +126 -0
- package/node_modules/zod/src/v4/locales/tr.ts +121 -0
- package/node_modules/zod/src/v4/locales/ua.ts +126 -0
- package/node_modules/zod/src/v4/locales/ur.ts +126 -0
- package/node_modules/zod/src/v4/locales/vi.ts +125 -0
- package/node_modules/zod/src/v4/locales/zh-CN.ts +123 -0
- package/node_modules/zod/src/v4/locales/zh-TW.ts +125 -0
- package/node_modules/zod/src/v4/mini/checks.ts +32 -0
- package/node_modules/zod/src/v4/mini/coerce.ts +22 -0
- package/node_modules/zod/src/v4/mini/external.ts +40 -0
- package/node_modules/zod/src/v4/mini/index.ts +3 -0
- package/node_modules/zod/src/v4/mini/iso.ts +62 -0
- package/node_modules/zod/src/v4/mini/parse.ts +1 -0
- package/node_modules/zod/src/v4/mini/schemas.ts +1579 -0
- package/node_modules/zod/src/v4/mini/tests/assignability.test.ts +129 -0
- package/node_modules/zod/src/v4/mini/tests/brand.test.ts +51 -0
- package/node_modules/zod/src/v4/mini/tests/checks.test.ts +144 -0
- package/node_modules/zod/src/v4/mini/tests/computed.test.ts +36 -0
- package/node_modules/zod/src/v4/mini/tests/error.test.ts +22 -0
- package/node_modules/zod/src/v4/mini/tests/functions.test.ts +43 -0
- package/node_modules/zod/src/v4/mini/tests/index.test.ts +871 -0
- package/node_modules/zod/src/v4/mini/tests/number.test.ts +95 -0
- package/node_modules/zod/src/v4/mini/tests/object.test.ts +185 -0
- package/node_modules/zod/src/v4/mini/tests/prototypes.test.ts +43 -0
- package/node_modules/zod/src/v4/mini/tests/recursive-types.test.ts +275 -0
- package/node_modules/zod/src/v4/mini/tests/string.test.ts +299 -0
- package/node_modules/zod/src/v4-mini/index.ts +1 -0
- package/node_modules/zod/v3/ZodError.cjs +138 -0
- package/node_modules/zod/v3/ZodError.d.cts +164 -0
- package/node_modules/zod/v3/ZodError.d.ts +164 -0
- package/node_modules/zod/v3/ZodError.js +133 -0
- package/node_modules/zod/v3/errors.cjs +17 -0
- package/node_modules/zod/v3/errors.d.cts +5 -0
- package/node_modules/zod/v3/errors.d.ts +5 -0
- package/node_modules/zod/v3/errors.js +9 -0
- package/node_modules/zod/v3/external.cjs +22 -0
- package/node_modules/zod/v3/external.d.cts +6 -0
- package/node_modules/zod/v3/external.d.ts +6 -0
- package/node_modules/zod/v3/external.js +6 -0
- package/node_modules/zod/v3/helpers/enumUtil.cjs +2 -0
- package/node_modules/zod/v3/helpers/enumUtil.d.cts +8 -0
- package/node_modules/zod/v3/helpers/enumUtil.d.ts +8 -0
- package/node_modules/zod/v3/helpers/enumUtil.js +1 -0
- package/node_modules/zod/v3/helpers/errorUtil.cjs +9 -0
- package/node_modules/zod/v3/helpers/errorUtil.d.cts +9 -0
- package/node_modules/zod/v3/helpers/errorUtil.d.ts +9 -0
- package/node_modules/zod/v3/helpers/errorUtil.js +6 -0
- package/node_modules/zod/v3/helpers/parseUtil.cjs +124 -0
- package/node_modules/zod/v3/helpers/parseUtil.d.cts +78 -0
- package/node_modules/zod/v3/helpers/parseUtil.d.ts +78 -0
- package/node_modules/zod/v3/helpers/parseUtil.js +109 -0
- package/node_modules/zod/v3/helpers/partialUtil.cjs +2 -0
- package/node_modules/zod/v3/helpers/partialUtil.d.cts +8 -0
- package/node_modules/zod/v3/helpers/partialUtil.d.ts +8 -0
- package/node_modules/zod/v3/helpers/partialUtil.js +1 -0
- package/node_modules/zod/v3/helpers/typeAliases.cjs +2 -0
- package/node_modules/zod/v3/helpers/typeAliases.d.cts +2 -0
- package/node_modules/zod/v3/helpers/typeAliases.d.ts +2 -0
- package/node_modules/zod/v3/helpers/typeAliases.js +1 -0
- package/node_modules/zod/v3/helpers/util.cjs +137 -0
- package/node_modules/zod/v3/helpers/util.d.cts +85 -0
- package/node_modules/zod/v3/helpers/util.d.ts +85 -0
- package/node_modules/zod/v3/helpers/util.js +133 -0
- package/node_modules/zod/v3/index.cjs +33 -0
- package/node_modules/zod/v3/index.d.cts +4 -0
- package/node_modules/zod/v3/index.d.ts +4 -0
- package/node_modules/zod/v3/index.js +4 -0
- package/node_modules/zod/v3/locales/en.cjs +111 -0
- package/node_modules/zod/v3/locales/en.d.cts +3 -0
- package/node_modules/zod/v3/locales/en.d.ts +3 -0
- package/node_modules/zod/v3/locales/en.js +109 -0
- package/node_modules/zod/v3/standard-schema.cjs +2 -0
- package/node_modules/zod/v3/standard-schema.d.cts +102 -0
- package/node_modules/zod/v3/standard-schema.d.ts +102 -0
- package/node_modules/zod/v3/standard-schema.js +1 -0
- package/node_modules/zod/v3/types.cjs +3775 -0
- package/node_modules/zod/v3/types.d.cts +1031 -0
- package/node_modules/zod/v3/types.d.ts +1031 -0
- package/node_modules/zod/v3/types.js +3693 -0
- package/node_modules/zod/v4/classic/checks.cjs +32 -0
- package/node_modules/zod/v4/classic/checks.d.cts +1 -0
- package/node_modules/zod/v4/classic/checks.d.ts +1 -0
- package/node_modules/zod/v4/classic/checks.js +1 -0
- package/node_modules/zod/v4/classic/coerce.cjs +47 -0
- package/node_modules/zod/v4/classic/coerce.d.cts +17 -0
- package/node_modules/zod/v4/classic/coerce.d.ts +17 -0
- package/node_modules/zod/v4/classic/coerce.js +17 -0
- package/node_modules/zod/v4/classic/compat.cjs +57 -0
- package/node_modules/zod/v4/classic/compat.d.cts +46 -0
- package/node_modules/zod/v4/classic/compat.d.ts +46 -0
- package/node_modules/zod/v4/classic/compat.js +27 -0
- package/node_modules/zod/v4/classic/errors.cjs +67 -0
- package/node_modules/zod/v4/classic/errors.d.cts +30 -0
- package/node_modules/zod/v4/classic/errors.d.ts +30 -0
- package/node_modules/zod/v4/classic/errors.js +41 -0
- package/node_modules/zod/v4/classic/external.cjs +70 -0
- package/node_modules/zod/v4/classic/external.d.cts +13 -0
- package/node_modules/zod/v4/classic/external.d.ts +13 -0
- package/node_modules/zod/v4/classic/external.js +18 -0
- package/node_modules/zod/v4/classic/index.cjs +33 -0
- package/node_modules/zod/v4/classic/index.d.cts +4 -0
- package/node_modules/zod/v4/classic/index.d.ts +4 -0
- package/node_modules/zod/v4/classic/index.js +4 -0
- package/node_modules/zod/v4/classic/iso.cjs +60 -0
- package/node_modules/zod/v4/classic/iso.d.cts +22 -0
- package/node_modules/zod/v4/classic/iso.d.ts +22 -0
- package/node_modules/zod/v4/classic/iso.js +30 -0
- package/node_modules/zod/v4/classic/parse.cjs +32 -0
- package/node_modules/zod/v4/classic/parse.d.cts +23 -0
- package/node_modules/zod/v4/classic/parse.d.ts +23 -0
- package/node_modules/zod/v4/classic/parse.js +6 -0
- package/node_modules/zod/v4/classic/schemas.cjs +1109 -0
- package/node_modules/zod/v4/classic/schemas.d.cts +630 -0
- package/node_modules/zod/v4/classic/schemas.d.ts +630 -0
- package/node_modules/zod/v4/classic/schemas.js +1006 -0
- package/node_modules/zod/v4/core/api.cjs +1039 -0
- package/node_modules/zod/v4/core/api.d.cts +284 -0
- package/node_modules/zod/v4/core/api.d.ts +284 -0
- package/node_modules/zod/v4/core/api.js +906 -0
- package/node_modules/zod/v4/core/checks.cjs +591 -0
- package/node_modules/zod/v4/core/checks.d.cts +278 -0
- package/node_modules/zod/v4/core/checks.d.ts +278 -0
- package/node_modules/zod/v4/core/checks.js +565 -0
- package/node_modules/zod/v4/core/core.cjs +67 -0
- package/node_modules/zod/v4/core/core.d.cts +49 -0
- package/node_modules/zod/v4/core/core.d.ts +49 -0
- package/node_modules/zod/v4/core/core.js +61 -0
- package/node_modules/zod/v4/core/doc.cjs +39 -0
- package/node_modules/zod/v4/core/doc.d.cts +14 -0
- package/node_modules/zod/v4/core/doc.d.ts +14 -0
- package/node_modules/zod/v4/core/doc.js +35 -0
- package/node_modules/zod/v4/core/errors.cjs +226 -0
- package/node_modules/zod/v4/core/errors.d.cts +208 -0
- package/node_modules/zod/v4/core/errors.d.ts +208 -0
- package/node_modules/zod/v4/core/errors.js +195 -0
- package/node_modules/zod/v4/core/function.cjs +102 -0
- package/node_modules/zod/v4/core/function.d.cts +52 -0
- package/node_modules/zod/v4/core/function.d.ts +52 -0
- package/node_modules/zod/v4/core/function.js +75 -0
- package/node_modules/zod/v4/core/index.cjs +44 -0
- package/node_modules/zod/v4/core/index.d.cts +15 -0
- package/node_modules/zod/v4/core/index.d.ts +15 -0
- package/node_modules/zod/v4/core/index.js +15 -0
- package/node_modules/zod/v4/core/json-schema.cjs +2 -0
- package/node_modules/zod/v4/core/json-schema.d.cts +87 -0
- package/node_modules/zod/v4/core/json-schema.d.ts +87 -0
- package/node_modules/zod/v4/core/json-schema.js +1 -0
- package/node_modules/zod/v4/core/parse.cjs +87 -0
- package/node_modules/zod/v4/core/parse.d.cts +25 -0
- package/node_modules/zod/v4/core/parse.d.ts +25 -0
- package/node_modules/zod/v4/core/parse.js +57 -0
- package/node_modules/zod/v4/core/regexes.cjs +103 -0
- package/node_modules/zod/v4/core/regexes.d.cts +62 -0
- package/node_modules/zod/v4/core/regexes.d.ts +62 -0
- package/node_modules/zod/v4/core/regexes.js +95 -0
- package/node_modules/zod/v4/core/registries.cjs +56 -0
- package/node_modules/zod/v4/core/registries.d.cts +35 -0
- package/node_modules/zod/v4/core/registries.d.ts +35 -0
- package/node_modules/zod/v4/core/registries.js +51 -0
- package/node_modules/zod/v4/core/schemas.cjs +1748 -0
- package/node_modules/zod/v4/core/schemas.d.cts +1041 -0
- package/node_modules/zod/v4/core/schemas.d.ts +1041 -0
- package/node_modules/zod/v4/core/schemas.js +1717 -0
- package/node_modules/zod/v4/core/standard-schema.cjs +2 -0
- package/node_modules/zod/v4/core/standard-schema.d.cts +55 -0
- package/node_modules/zod/v4/core/standard-schema.d.ts +55 -0
- package/node_modules/zod/v4/core/standard-schema.js +1 -0
- package/node_modules/zod/v4/core/to-json-schema.cjs +854 -0
- package/node_modules/zod/v4/core/to-json-schema.d.cts +88 -0
- package/node_modules/zod/v4/core/to-json-schema.d.ts +88 -0
- package/node_modules/zod/v4/core/to-json-schema.js +849 -0
- package/node_modules/zod/v4/core/util.cjs +539 -0
- package/node_modules/zod/v4/core/util.d.cts +183 -0
- package/node_modules/zod/v4/core/util.d.ts +183 -0
- package/node_modules/zod/v4/core/util.js +493 -0
- package/node_modules/zod/v4/core/versions.cjs +8 -0
- package/node_modules/zod/v4/core/versions.d.cts +5 -0
- package/node_modules/zod/v4/core/versions.d.ts +5 -0
- package/node_modules/zod/v4/core/versions.js +5 -0
- package/node_modules/zod/v4/index.cjs +22 -0
- package/node_modules/zod/v4/index.d.cts +3 -0
- package/node_modules/zod/v4/index.d.ts +3 -0
- package/node_modules/zod/v4/index.js +3 -0
- package/node_modules/zod/v4/locales/ar.cjs +142 -0
- package/node_modules/zod/v4/locales/ar.d.cts +4 -0
- package/node_modules/zod/v4/locales/ar.d.ts +4 -0
- package/node_modules/zod/v4/locales/ar.js +116 -0
- package/node_modules/zod/v4/locales/az.cjs +141 -0
- package/node_modules/zod/v4/locales/az.d.cts +4 -0
- package/node_modules/zod/v4/locales/az.d.ts +4 -0
- package/node_modules/zod/v4/locales/az.js +115 -0
- package/node_modules/zod/v4/locales/be.cjs +190 -0
- package/node_modules/zod/v4/locales/be.d.cts +4 -0
- package/node_modules/zod/v4/locales/be.d.ts +4 -0
- package/node_modules/zod/v4/locales/be.js +164 -0
- package/node_modules/zod/v4/locales/ca.cjs +144 -0
- package/node_modules/zod/v4/locales/ca.d.cts +4 -0
- package/node_modules/zod/v4/locales/ca.d.ts +4 -0
- package/node_modules/zod/v4/locales/ca.js +118 -0
- package/node_modules/zod/v4/locales/cs.cjs +161 -0
- package/node_modules/zod/v4/locales/cs.d.cts +4 -0
- package/node_modules/zod/v4/locales/cs.d.ts +4 -0
- package/node_modules/zod/v4/locales/cs.js +135 -0
- package/node_modules/zod/v4/locales/de.cjs +142 -0
- package/node_modules/zod/v4/locales/de.d.cts +4 -0
- package/node_modules/zod/v4/locales/de.d.ts +4 -0
- package/node_modules/zod/v4/locales/de.js +116 -0
- package/node_modules/zod/v4/locales/en.cjs +145 -0
- package/node_modules/zod/v4/locales/en.d.cts +5 -0
- package/node_modules/zod/v4/locales/en.d.ts +5 -0
- package/node_modules/zod/v4/locales/en.js +117 -0
- package/node_modules/zod/v4/locales/eo.cjs +144 -0
- package/node_modules/zod/v4/locales/eo.d.cts +5 -0
- package/node_modules/zod/v4/locales/eo.d.ts +5 -0
- package/node_modules/zod/v4/locales/eo.js +116 -0
- package/node_modules/zod/v4/locales/es.cjs +143 -0
- package/node_modules/zod/v4/locales/es.d.cts +4 -0
- package/node_modules/zod/v4/locales/es.d.ts +4 -0
- package/node_modules/zod/v4/locales/es.js +117 -0
- package/node_modules/zod/v4/locales/fa.cjs +148 -0
- package/node_modules/zod/v4/locales/fa.d.cts +4 -0
- package/node_modules/zod/v4/locales/fa.d.ts +4 -0
- package/node_modules/zod/v4/locales/fa.js +122 -0
- package/node_modules/zod/v4/locales/fi.cjs +148 -0
- package/node_modules/zod/v4/locales/fi.d.cts +4 -0
- package/node_modules/zod/v4/locales/fi.d.ts +4 -0
- package/node_modules/zod/v4/locales/fi.js +122 -0
- package/node_modules/zod/v4/locales/fr-CA.cjs +143 -0
- package/node_modules/zod/v4/locales/fr-CA.d.cts +4 -0
- package/node_modules/zod/v4/locales/fr-CA.d.ts +4 -0
- package/node_modules/zod/v4/locales/fr-CA.js +117 -0
- package/node_modules/zod/v4/locales/fr.cjs +142 -0
- package/node_modules/zod/v4/locales/fr.d.cts +4 -0
- package/node_modules/zod/v4/locales/fr.d.ts +4 -0
- package/node_modules/zod/v4/locales/fr.js +116 -0
- package/node_modules/zod/v4/locales/he.cjs +143 -0
- package/node_modules/zod/v4/locales/he.d.cts +4 -0
- package/node_modules/zod/v4/locales/he.d.ts +4 -0
- package/node_modules/zod/v4/locales/he.js +117 -0
- package/node_modules/zod/v4/locales/hu.cjs +143 -0
- package/node_modules/zod/v4/locales/hu.d.cts +4 -0
- package/node_modules/zod/v4/locales/hu.d.ts +4 -0
- package/node_modules/zod/v4/locales/hu.js +117 -0
- package/node_modules/zod/v4/locales/id.cjs +142 -0
- package/node_modules/zod/v4/locales/id.d.cts +4 -0
- package/node_modules/zod/v4/locales/id.d.ts +4 -0
- package/node_modules/zod/v4/locales/id.js +116 -0
- package/node_modules/zod/v4/locales/index.cjs +84 -0
- package/node_modules/zod/v4/locales/index.d.cts +39 -0
- package/node_modules/zod/v4/locales/index.d.ts +39 -0
- package/node_modules/zod/v4/locales/index.js +39 -0
- package/node_modules/zod/v4/locales/it.cjs +143 -0
- package/node_modules/zod/v4/locales/it.d.cts +4 -0
- package/node_modules/zod/v4/locales/it.d.ts +4 -0
- package/node_modules/zod/v4/locales/it.js +117 -0
- package/node_modules/zod/v4/locales/ja.cjs +141 -0
- package/node_modules/zod/v4/locales/ja.d.cts +4 -0
- package/node_modules/zod/v4/locales/ja.d.ts +4 -0
- package/node_modules/zod/v4/locales/ja.js +115 -0
- package/node_modules/zod/v4/locales/kh.cjs +143 -0
- package/node_modules/zod/v4/locales/kh.d.cts +4 -0
- package/node_modules/zod/v4/locales/kh.d.ts +4 -0
- package/node_modules/zod/v4/locales/kh.js +117 -0
- package/node_modules/zod/v4/locales/ko.cjs +147 -0
- package/node_modules/zod/v4/locales/ko.d.cts +4 -0
- package/node_modules/zod/v4/locales/ko.d.ts +4 -0
- package/node_modules/zod/v4/locales/ko.js +121 -0
- package/node_modules/zod/v4/locales/mk.cjs +144 -0
- package/node_modules/zod/v4/locales/mk.d.cts +4 -0
- package/node_modules/zod/v4/locales/mk.d.ts +4 -0
- package/node_modules/zod/v4/locales/mk.js +118 -0
- package/node_modules/zod/v4/locales/ms.cjs +142 -0
- package/node_modules/zod/v4/locales/ms.d.cts +4 -0
- package/node_modules/zod/v4/locales/ms.d.ts +4 -0
- package/node_modules/zod/v4/locales/ms.js +116 -0
- package/node_modules/zod/v4/locales/nl.cjs +143 -0
- package/node_modules/zod/v4/locales/nl.d.cts +4 -0
- package/node_modules/zod/v4/locales/nl.d.ts +4 -0
- package/node_modules/zod/v4/locales/nl.js +117 -0
- package/node_modules/zod/v4/locales/no.cjs +142 -0
- package/node_modules/zod/v4/locales/no.d.cts +4 -0
- package/node_modules/zod/v4/locales/no.d.ts +4 -0
- package/node_modules/zod/v4/locales/no.js +116 -0
- package/node_modules/zod/v4/locales/ota.cjs +143 -0
- package/node_modules/zod/v4/locales/ota.d.cts +4 -0
- package/node_modules/zod/v4/locales/ota.d.ts +4 -0
- package/node_modules/zod/v4/locales/ota.js +117 -0
- package/node_modules/zod/v4/locales/pl.cjs +143 -0
- package/node_modules/zod/v4/locales/pl.d.cts +4 -0
- package/node_modules/zod/v4/locales/pl.d.ts +4 -0
- package/node_modules/zod/v4/locales/pl.js +117 -0
- package/node_modules/zod/v4/locales/ps.cjs +148 -0
- package/node_modules/zod/v4/locales/ps.d.cts +4 -0
- package/node_modules/zod/v4/locales/ps.d.ts +4 -0
- package/node_modules/zod/v4/locales/ps.js +122 -0
- package/node_modules/zod/v4/locales/pt.cjs +142 -0
- package/node_modules/zod/v4/locales/pt.d.cts +4 -0
- package/node_modules/zod/v4/locales/pt.d.ts +4 -0
- package/node_modules/zod/v4/locales/pt.js +116 -0
- package/node_modules/zod/v4/locales/ru.cjs +190 -0
- package/node_modules/zod/v4/locales/ru.d.cts +4 -0
- package/node_modules/zod/v4/locales/ru.d.ts +4 -0
- package/node_modules/zod/v4/locales/ru.js +164 -0
- package/node_modules/zod/v4/locales/sl.cjs +143 -0
- package/node_modules/zod/v4/locales/sl.d.cts +4 -0
- package/node_modules/zod/v4/locales/sl.d.ts +4 -0
- package/node_modules/zod/v4/locales/sl.js +117 -0
- package/node_modules/zod/v4/locales/sv.cjs +144 -0
- package/node_modules/zod/v4/locales/sv.d.cts +4 -0
- package/node_modules/zod/v4/locales/sv.d.ts +4 -0
- package/node_modules/zod/v4/locales/sv.js +118 -0
- package/node_modules/zod/v4/locales/ta.cjs +143 -0
- package/node_modules/zod/v4/locales/ta.d.cts +4 -0
- package/node_modules/zod/v4/locales/ta.d.ts +4 -0
- package/node_modules/zod/v4/locales/ta.js +117 -0
- package/node_modules/zod/v4/locales/th.cjs +143 -0
- package/node_modules/zod/v4/locales/th.d.cts +4 -0
- package/node_modules/zod/v4/locales/th.d.ts +4 -0
- package/node_modules/zod/v4/locales/th.js +117 -0
- package/node_modules/zod/v4/locales/tr.cjs +143 -0
- package/node_modules/zod/v4/locales/tr.d.cts +5 -0
- package/node_modules/zod/v4/locales/tr.d.ts +5 -0
- package/node_modules/zod/v4/locales/tr.js +115 -0
- package/node_modules/zod/v4/locales/ua.cjs +143 -0
- package/node_modules/zod/v4/locales/ua.d.cts +4 -0
- package/node_modules/zod/v4/locales/ua.d.ts +4 -0
- package/node_modules/zod/v4/locales/ua.js +117 -0
- package/node_modules/zod/v4/locales/ur.cjs +143 -0
- package/node_modules/zod/v4/locales/ur.d.cts +4 -0
- package/node_modules/zod/v4/locales/ur.d.ts +4 -0
- package/node_modules/zod/v4/locales/ur.js +117 -0
- package/node_modules/zod/v4/locales/vi.cjs +142 -0
- package/node_modules/zod/v4/locales/vi.d.cts +4 -0
- package/node_modules/zod/v4/locales/vi.d.ts +4 -0
- package/node_modules/zod/v4/locales/vi.js +116 -0
- package/node_modules/zod/v4/locales/zh-CN.cjs +142 -0
- package/node_modules/zod/v4/locales/zh-CN.d.cts +4 -0
- package/node_modules/zod/v4/locales/zh-CN.d.ts +4 -0
- package/node_modules/zod/v4/locales/zh-CN.js +116 -0
- package/node_modules/zod/v4/locales/zh-TW.cjs +143 -0
- package/node_modules/zod/v4/locales/zh-TW.d.cts +4 -0
- package/node_modules/zod/v4/locales/zh-TW.d.ts +4 -0
- package/node_modules/zod/v4/locales/zh-TW.js +117 -0
- package/node_modules/zod/v4/mini/checks.cjs +34 -0
- package/node_modules/zod/v4/mini/checks.d.cts +1 -0
- package/node_modules/zod/v4/mini/checks.d.ts +1 -0
- package/node_modules/zod/v4/mini/checks.js +1 -0
- package/node_modules/zod/v4/mini/coerce.cjs +47 -0
- package/node_modules/zod/v4/mini/coerce.d.cts +7 -0
- package/node_modules/zod/v4/mini/coerce.d.ts +7 -0
- package/node_modules/zod/v4/mini/coerce.js +17 -0
- package/node_modules/zod/v4/mini/external.cjs +62 -0
- package/node_modules/zod/v4/mini/external.d.cts +11 -0
- package/node_modules/zod/v4/mini/external.d.ts +11 -0
- package/node_modules/zod/v4/mini/external.js +13 -0
- package/node_modules/zod/v4/mini/index.cjs +32 -0
- package/node_modules/zod/v4/mini/index.d.cts +3 -0
- package/node_modules/zod/v4/mini/index.d.ts +3 -0
- package/node_modules/zod/v4/mini/index.js +3 -0
- package/node_modules/zod/v4/mini/iso.cjs +60 -0
- package/node_modules/zod/v4/mini/iso.d.cts +22 -0
- package/node_modules/zod/v4/mini/iso.d.ts +22 -0
- package/node_modules/zod/v4/mini/iso.js +30 -0
- package/node_modules/zod/v4/mini/parse.cjs +8 -0
- package/node_modules/zod/v4/mini/parse.d.cts +1 -0
- package/node_modules/zod/v4/mini/parse.d.ts +1 -0
- package/node_modules/zod/v4/mini/parse.js +1 -0
- package/node_modules/zod/v4/mini/schemas.cjs +839 -0
- package/node_modules/zod/v4/mini/schemas.d.cts +356 -0
- package/node_modules/zod/v4/mini/schemas.d.ts +356 -0
- package/node_modules/zod/v4/mini/schemas.js +732 -0
- package/node_modules/zod/v4-mini/index.cjs +17 -0
- package/node_modules/zod/v4-mini/index.d.cts +1 -0
- package/node_modules/zod/v4-mini/index.d.ts +1 -0
- package/node_modules/zod/v4-mini/index.js +1 -0
- package/package.json +100 -101
- package/dist/index-DXag5A9X.js +0 -1096
|
@@ -0,0 +1,3205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview 引用复合预览绑定 - 提供截图复合卡片的分类、布局和高密度数据整理 helper。
|
|
3
|
+
* @author seadon
|
|
4
|
+
* @created 2026-05-20
|
|
5
|
+
*/
|
|
6
|
+
import type { CSSProperties } from 'vue';
|
|
7
|
+
import type { CustomCanvasData, CustomCanvasNestedBlock, WorkbenchBlock } from '../../types';
|
|
8
|
+
import { createReferenceRiskAndStrategyBindings } from './referenceRiskAndStrategyBindings';
|
|
9
|
+
|
|
10
|
+
type ReferenceCompositeContext = Record<string, any>;
|
|
11
|
+
type NestedBlockVisualKind =
|
|
12
|
+
| 'metric'
|
|
13
|
+
| 'table'
|
|
14
|
+
| 'list'
|
|
15
|
+
| 'chart'
|
|
16
|
+
| 'statusList'
|
|
17
|
+
| 'incidentList'
|
|
18
|
+
| 'resourceBars'
|
|
19
|
+
| 'securityScore'
|
|
20
|
+
| 'simpleList'
|
|
21
|
+
| 'progressList'
|
|
22
|
+
| 'todoGrid'
|
|
23
|
+
| 'quickLinks'
|
|
24
|
+
| 'donut'
|
|
25
|
+
| 'summary';
|
|
26
|
+
|
|
27
|
+
type ReferenceCompositeRegion = {
|
|
28
|
+
left: string;
|
|
29
|
+
top: string;
|
|
30
|
+
width: string;
|
|
31
|
+
height: string;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Creates helpers for reference-style composite previews.
|
|
36
|
+
* @param context - Shared renderer helpers from the main workbench block binding.
|
|
37
|
+
* @returns Reference composite helper functions consumed by the template.
|
|
38
|
+
*/
|
|
39
|
+
export function createReferenceCompositeBindings(context: ReferenceCompositeContext) {
|
|
40
|
+
const {
|
|
41
|
+
textValue,
|
|
42
|
+
numberValue,
|
|
43
|
+
isRecord,
|
|
44
|
+
imageComposeCompactCard,
|
|
45
|
+
customCanvasRiskSummaryBand,
|
|
46
|
+
nestedBlockClassifierText,
|
|
47
|
+
nestedBlockDataSummary,
|
|
48
|
+
nestedBlockRawItems,
|
|
49
|
+
nestedBlockItemTitle,
|
|
50
|
+
nestedBlockVisualKind,
|
|
51
|
+
nestedBlockPreviewKind,
|
|
52
|
+
customCanvasVisibleNarrative,
|
|
53
|
+
customCanvasHasNestedBlocks,
|
|
54
|
+
customCanvasVisibleElements,
|
|
55
|
+
imageComposeAlertRankingTitle,
|
|
56
|
+
visualFor,
|
|
57
|
+
recordHasImageComposeSource,
|
|
58
|
+
customCanvasGeneratedElement,
|
|
59
|
+
nestedBlockMetricValue,
|
|
60
|
+
nestedBlockItemValue,
|
|
61
|
+
nestedBlockItemDetail,
|
|
62
|
+
nestedBlockItemLabel,
|
|
63
|
+
nestedBlockToneFromStatus,
|
|
64
|
+
nestedBlockNeedsHumanIntervention,
|
|
65
|
+
nestedBlockItems,
|
|
66
|
+
nestedBlockItemsLookTooWeak,
|
|
67
|
+
nestedBlockItemsLookTooWeakForVisualKind,
|
|
68
|
+
nestedBlockFallbackItems,
|
|
69
|
+
nestedBlockElementItems,
|
|
70
|
+
nestedBlockBarItems,
|
|
71
|
+
nestedBlockOptionalNumber,
|
|
72
|
+
nestedBlockNumber,
|
|
73
|
+
nestedBlockDisplayValue,
|
|
74
|
+
nestedBlockDonutItems,
|
|
75
|
+
} = context;
|
|
76
|
+
|
|
77
|
+
type ReferenceCompositeKind =
|
|
78
|
+
| 'ops'
|
|
79
|
+
| 'security'
|
|
80
|
+
| 'asset'
|
|
81
|
+
| 'project'
|
|
82
|
+
| 'bidCollaboration'
|
|
83
|
+
| 'riskSummary'
|
|
84
|
+
| 'healthRadar'
|
|
85
|
+
| 'deviation'
|
|
86
|
+
| 'financeRisk'
|
|
87
|
+
| 'expenseRisk'
|
|
88
|
+
| 'deviationInsight'
|
|
89
|
+
| 'organizationRisk'
|
|
90
|
+
| 'investmentRisk'
|
|
91
|
+
| 'executiveTodo'
|
|
92
|
+
| 'shortcutDrill'
|
|
93
|
+
| 'quickWorkbench'
|
|
94
|
+
| 'strategyKpi'
|
|
95
|
+
| 'operationHealth'
|
|
96
|
+
| 'operationEfficiency'
|
|
97
|
+
| 'businessMetricMatrix'
|
|
98
|
+
| 'hrOrganization'
|
|
99
|
+
| 'hrRiskCompliance'
|
|
100
|
+
| 'hrPeopleCost'
|
|
101
|
+
| 'hrTalentTodo'
|
|
102
|
+
| '';
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Checks whether a dense image container should use a reference-style composite preview.
|
|
106
|
+
* @param block - Rendered customCanvas container.
|
|
107
|
+
* @param data - Custom canvas renderer data.
|
|
108
|
+
* @returns True for dense CIO asset/project panels that should not show every micro-card as a large child card.
|
|
109
|
+
*/
|
|
110
|
+
function customCanvasUsesReferenceCompositePreview(block: WorkbenchBlock, data: CustomCanvasData): boolean {
|
|
111
|
+
return customCanvasReferenceCompositeKind(block, data) !== '';
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Classifies a dense screenshot container into a reference-style composite family.
|
|
116
|
+
* @param block - Rendered customCanvas container.
|
|
117
|
+
* @param data - Custom canvas renderer data.
|
|
118
|
+
* @returns Composite family id, or empty string when normal nested cards should render.
|
|
119
|
+
*/
|
|
120
|
+
function customCanvasReferenceCompositeKind(block: WorkbenchBlock, data: CustomCanvasData): ReferenceCompositeKind {
|
|
121
|
+
const nestedBlocks = Array.isArray(data.nestedBlocks) ? data.nestedBlocks : [];
|
|
122
|
+
if (!imageComposeCompactCard(block)) return '';
|
|
123
|
+
const parentKind = referenceCompositeKindFromContainerTitle(block.title);
|
|
124
|
+
const automaticImageSource = referenceCompositeUsesAutomaticImageSource(block, data);
|
|
125
|
+
if (automaticImageSource && parentKind === 'bidCollaboration') return '';
|
|
126
|
+
if (customCanvasLooksLikeRiskSummaryTitle(block)) return 'riskSummary';
|
|
127
|
+
if (automaticImageSource && !parentKind) {
|
|
128
|
+
const explicitKind = referenceCompositeKindFromVisualKind(block, data);
|
|
129
|
+
return explicitKind && referenceCompositeKindAllowedForBlock(explicitKind, block, data) ? explicitKind : '';
|
|
130
|
+
}
|
|
131
|
+
if (customCanvasLooksLikeStandaloneQuickLinks(block, data)) return '';
|
|
132
|
+
if (parentKind && referenceCompositeKindAllowedForBlock(parentKind, block, data)) return parentKind;
|
|
133
|
+
if (customCanvasRiskSummaryBand(block, data) && referenceCompositeLooksLikeChairmanRiskDirectContext(block, data)) return 'riskSummary';
|
|
134
|
+
if (customCanvasLooksLikePageHeader(block, data)) return '';
|
|
135
|
+
if (customCanvasLooksLikeBidCollaboration(block, data)) return 'bidCollaboration';
|
|
136
|
+
if (customCanvasLooksLikeBusinessMetricMatrix(block, data)) return 'businessMetricMatrix';
|
|
137
|
+
const text = referenceCompositeSearchText(block, data);
|
|
138
|
+
if (/快捷工作台|快捷入口|入口导航|待办入口|常用报表|系统入口|消息中心/.test(text)) return 'quickWorkbench';
|
|
139
|
+
if (/战略\s*KPI|KPI\s*看板|战略KPI看板|经营KPI|核心指标看板|目标完成率|营业收入/.test(text)) return 'strategyKpi';
|
|
140
|
+
if (/经营健康度|经营健康|健康度/.test(text)) return 'operationHealth';
|
|
141
|
+
if (/组织编制|人员结构|编制使用|平均司龄|部门编制|关键异动/.test(text) && referenceCompositeLooksLikeHrContext(block, data)) return 'hrOrganization';
|
|
142
|
+
if (/人力风险|用工风险|用工合规|考勤异常|劳动纠纷|合规管控|迟到|旷工|请假/.test(text) && referenceCompositeLooksLikeHrContext(block, data)) return 'hrRiskCompliance';
|
|
143
|
+
if (/人数.*薪酬|薪酬成本|薪酬结构|人力总成本|成本趋势|人效排行/.test(text) && referenceCompositeLooksLikeHrContext(block, data)) return 'hrPeopleCost';
|
|
144
|
+
if (/人才发展|待办中心|人才梯队|继任计划|储备干部|培训完成|人事待办|快捷入口/.test(text) && referenceCompositeLooksLikeHrContext(block, data)) return 'hrTalentTodo';
|
|
145
|
+
if (/运营效率|交付|履约|资源利用|重点项目里程碑|订单准时|生产良率|服务响应|人均产值|设备利用|库存周转|数字化工厂|成本专项|渠道升级|新品上市/.test(text) && !referenceCompositeLooksLikeHrPeopleCostContext(block, data)) return 'operationEfficiency';
|
|
146
|
+
if (/快捷穿透|风险全景下钻|二级页|亏损主体|组织隐患/.test(text) && referenceCompositeLooksLikeChairmanRiskContext(block, data)) return 'shortcutDrill';
|
|
147
|
+
if (/五大维度|健康雷达|雷达|盈利结构|资金安全边际/.test(text) && referenceCompositeLooksLikeChairmanRiskContext(block, data)) return 'healthRadar';
|
|
148
|
+
if (/经营目标偏差|目标完成|目标\s*VS\s*实际|利润底线|目标偏差/.test(text) && referenceCompositeLooksLikeChairmanRiskContext(block, data)) return 'deviation';
|
|
149
|
+
if (/财务资金|资金风险|逾期应收|现金流|坏账|风险红线/.test(text) && referenceCompositeLooksLikeChairmanRiskContext(block, data)) return 'financeRisk';
|
|
150
|
+
if (/偏差洞察|利润同比下滑|预算偏离/.test(text) && referenceCompositeLooksLikeChairmanRiskContext(block, data)) return 'deviationInsight';
|
|
151
|
+
if (/成本.*费用|费用超支|超阈值|费用超阈值|管理费用|外包成本/.test(text) && referenceCompositeLooksLikeChairmanRiskContext(block, data)) return 'expenseRisk';
|
|
152
|
+
if (/组织.*人效|人效风险|组织稳定|核心流失|人效下滑|超编/.test(text) && referenceCompositeLooksLikeChairmanRiskContext(block, data)) return 'organizationRisk';
|
|
153
|
+
if (/重大投资|项目风险|投资.*项目|战略项目|新基地|技改|甘特/.test(text) && referenceCompositeLooksLikeChairmanRiskContext(block, data)) return 'investmentRisk';
|
|
154
|
+
if (/高管重大待办|董事长督办|重大待办|战略投资追加|资金支付复核|待签批|待复核/.test(text) && referenceCompositeLooksLikeChairmanRiskContext(block, data)) return 'executiveTodo';
|
|
155
|
+
if (/数字化|项目|研发|效能|待办|审批|快捷|上线/.test(text) && referenceCompositeLooksLikeItContext(block, data)) return 'project';
|
|
156
|
+
if (/资产|成本|License|预算|云主机|机房|终端/.test(text) && referenceCompositeLooksLikeItContext(block, data)) return 'asset';
|
|
157
|
+
if (/信息安全|合规治理|安全风险|安全健康|账号|权限|审计|漏洞/.test(text) && referenceCompositeLooksLikeItContext(block, data)) return 'security';
|
|
158
|
+
if (nestedBlocks.length < 4) return '';
|
|
159
|
+
if (/基础设施|运维稳定|稳定性|服务监控|资源负载|CPU|内存|存储|带宽|故障.*告警|近七日故障/.test(text) && referenceCompositeLooksLikeItContext(block, data)) return 'ops';
|
|
160
|
+
return '';
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Checks whether a rendered customCanvas came from automatic image reconstruction.
|
|
165
|
+
* @param block - Rendered customCanvas container.
|
|
166
|
+
* @param data - Custom canvas renderer data.
|
|
167
|
+
* @returns True when screenshot keyword promotion must be disabled.
|
|
168
|
+
*/
|
|
169
|
+
function referenceCompositeUsesAutomaticImageSource(block: WorkbenchBlock, data: CustomCanvasData): boolean {
|
|
170
|
+
const meta = (isRecord(block.meta) ? block.meta : {}) as Record<string, unknown>;
|
|
171
|
+
const source = (isRecord(block.source) ? block.source : {}) as Record<string, unknown>;
|
|
172
|
+
if (meta.canvasRuntime === true || source.sourceType === 'canvas_runtime') return false;
|
|
173
|
+
return source.sourceType === 'ai_composition_v2'
|
|
174
|
+
|| source.service === 'workbench-v2'
|
|
175
|
+
|| recordHasImageComposeSource(block.meta)
|
|
176
|
+
|| recordHasImageComposeSource(block.source)
|
|
177
|
+
|| recordHasImageComposeSource(data)
|
|
178
|
+
|| (typeof block.source?.resourceKey === 'string' && block.source.resourceKey.startsWith('workbench.v2.image.'));
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Reads an explicit reference-composite visual kind from renderer metadata.
|
|
183
|
+
* @param block - Rendered customCanvas container.
|
|
184
|
+
* @param data - Custom canvas renderer data.
|
|
185
|
+
* @returns Reference composite kind when a trusted structured field declares it.
|
|
186
|
+
*/
|
|
187
|
+
function referenceCompositeKindFromVisualKind(block: WorkbenchBlock, data: CustomCanvasData): ReferenceCompositeKind {
|
|
188
|
+
const record = data as unknown as Record<string, unknown>;
|
|
189
|
+
const meta = (isRecord(block.meta) ? block.meta : {}) as Record<string, unknown>;
|
|
190
|
+
const visualKind = textValue(record.visualKind || meta.visualKind);
|
|
191
|
+
if (visualKind === 'quickWorkbench') return 'quickWorkbench';
|
|
192
|
+
if (visualKind === 'strategyKpi') return 'strategyKpi';
|
|
193
|
+
if (visualKind === 'operationHealth') return 'operationHealth';
|
|
194
|
+
if (visualKind === 'operationEfficiency') return 'operationEfficiency';
|
|
195
|
+
if (visualKind === 'riskSummary') return 'riskSummary';
|
|
196
|
+
return '';
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Builds a broad searchable text bundle for reference-template classification.
|
|
201
|
+
* @param block - Rendered customCanvas container.
|
|
202
|
+
* @param data - Custom canvas renderer data.
|
|
203
|
+
* @returns Parent, OCR element, and nested-card text joined into one classifier string.
|
|
204
|
+
*/
|
|
205
|
+
function referenceCompositeSearchText(block: WorkbenchBlock, data: CustomCanvasData): string {
|
|
206
|
+
const record = data as unknown as Record<string, unknown>;
|
|
207
|
+
const nestedBlocks = Array.isArray(data.nestedBlocks) ? data.nestedBlocks : [];
|
|
208
|
+
const elements = Array.isArray(data.elements) ? data.elements : [];
|
|
209
|
+
return [
|
|
210
|
+
block.title,
|
|
211
|
+
block.subtitle,
|
|
212
|
+
record.title,
|
|
213
|
+
record.subtitle,
|
|
214
|
+
data.narrative,
|
|
215
|
+
data.sourceLabel,
|
|
216
|
+
...elements.map(customCanvasTextElementValue),
|
|
217
|
+
...nestedBlocks.flatMap((nestedBlock) => [
|
|
218
|
+
nestedBlock.title,
|
|
219
|
+
nestedBlockClassifierText(nestedBlock),
|
|
220
|
+
nestedBlockDataSummary(nestedBlock),
|
|
221
|
+
...nestedBlockRawItems(nestedBlock).map((item: Record<string, unknown>, index: number) => nestedBlockItemTitle(item, index)),
|
|
222
|
+
]),
|
|
223
|
+
].map((value) => textValue(value)).filter(Boolean).join(' ');
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Checks whether a reference composite family is allowed for the current screenshot scene.
|
|
228
|
+
* @param kind - Candidate reference composite family.
|
|
229
|
+
* @param block - Rendered customCanvas container.
|
|
230
|
+
* @param data - Custom canvas renderer data.
|
|
231
|
+
* @returns True when the family is generic or the card text carries explicit CIO/IT context.
|
|
232
|
+
*/
|
|
233
|
+
function referenceCompositeKindAllowedForBlock(kind: ReferenceCompositeKind, block: WorkbenchBlock, data: CustomCanvasData): boolean {
|
|
234
|
+
if (kind === 'operationEfficiency' && referenceCompositeLooksLikeHrPeopleCostContext(block, data)) return false;
|
|
235
|
+
if (referenceCompositeKindRequiresItContext(kind)) return referenceCompositeLooksLikeItContext(block, data);
|
|
236
|
+
if (referenceCompositeKindRequiresChairmanRiskContext(kind)) return referenceCompositeLooksLikeChairmanRiskContext(block, data);
|
|
237
|
+
if (referenceCompositeKindRequiresHrContext(kind)) return referenceCompositeLooksLikeHrContext(block, data);
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Checks whether a reference family contains fixed IT/CIO copy and therefore needs scene context.
|
|
243
|
+
* @param kind - Candidate reference composite family.
|
|
244
|
+
* @returns True for templates whose visible copy is intentionally CIO/IT-specific.
|
|
245
|
+
*/
|
|
246
|
+
function referenceCompositeKindRequiresItContext(kind: ReferenceCompositeKind): boolean {
|
|
247
|
+
return kind === 'ops' || kind === 'security' || kind === 'asset' || kind === 'project';
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Checks whether a reference family contains fixed chairman-risk copy and therefore needs scene context.
|
|
252
|
+
* @param kind - Candidate reference composite family.
|
|
253
|
+
* @returns True for templates whose visible copy is intentionally chairman/risk-specific.
|
|
254
|
+
*/
|
|
255
|
+
function referenceCompositeKindRequiresChairmanRiskContext(kind: ReferenceCompositeKind): boolean {
|
|
256
|
+
return kind === 'riskSummary'
|
|
257
|
+
|| kind === 'healthRadar'
|
|
258
|
+
|| kind === 'deviation'
|
|
259
|
+
|| kind === 'financeRisk'
|
|
260
|
+
|| kind === 'expenseRisk'
|
|
261
|
+
|| kind === 'deviationInsight'
|
|
262
|
+
|| kind === 'organizationRisk'
|
|
263
|
+
|| kind === 'investmentRisk'
|
|
264
|
+
|| kind === 'executiveTodo'
|
|
265
|
+
|| kind === 'shortcutDrill';
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Checks whether a reference family contains fixed HR copy and therefore needs scene context.
|
|
270
|
+
* @param kind - Candidate reference composite family.
|
|
271
|
+
* @returns True for HR-specific templates.
|
|
272
|
+
*/
|
|
273
|
+
function referenceCompositeKindRequiresHrContext(kind: ReferenceCompositeKind): boolean {
|
|
274
|
+
return kind === 'hrOrganization'
|
|
275
|
+
|| kind === 'hrRiskCompliance'
|
|
276
|
+
|| kind === 'hrPeopleCost'
|
|
277
|
+
|| kind === 'hrTalentTodo';
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Detects explicit IT/CIO context before allowing fixed IT reference templates.
|
|
282
|
+
* @param block - Rendered customCanvas container.
|
|
283
|
+
* @param data - Custom canvas renderer data.
|
|
284
|
+
* @returns True when the parent or nested text indicates an IT workbench scene.
|
|
285
|
+
*/
|
|
286
|
+
function referenceCompositeLooksLikeItContext(block: WorkbenchBlock, data: CustomCanvasData): boolean {
|
|
287
|
+
const record = data as unknown as Record<string, unknown>;
|
|
288
|
+
const nestedBlocks = Array.isArray(data.nestedBlocks) ? data.nestedBlocks : [];
|
|
289
|
+
const text = [
|
|
290
|
+
block.title,
|
|
291
|
+
block.subtitle,
|
|
292
|
+
record.title,
|
|
293
|
+
record.subtitle,
|
|
294
|
+
data.narrative,
|
|
295
|
+
record.sourceLabel,
|
|
296
|
+
...nestedBlocks.map((nestedBlock) => nestedBlockClassifierText(nestedBlock)),
|
|
297
|
+
].map((value) => textValue(value)).filter(Boolean).join(' ');
|
|
298
|
+
return referenceCompositeTextHasItContext(text);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Checks whether text contains IT/CIO-specific terms instead of generic business words.
|
|
303
|
+
* @param text - Searchable parent and child text.
|
|
304
|
+
* @returns True when fixed CIO templates are safe to apply.
|
|
305
|
+
*/
|
|
306
|
+
function referenceCompositeTextHasItContext(text: string): boolean {
|
|
307
|
+
return /\b(CIO|IT)\b|信息化中心|IT\s*年度|IT\s*项目|IT\s*采购|IT\s*成本|IT\s*资产|系统上线审批|权限变更审批|安全整改待办|运维|研发|基础设施|服务监控|资源负载|机房|服务器|云主机|终端|License|软件|硬件|账号|权限|漏洞|攻击|网络安全|信息安全|安全事件|等保|堡垒机|服务工单|数据库|接口|中台|ERP|MES|WMS|SCM|CRM|ops|infrastructure|software|system|cyber|service desk/i.test(text);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Detects explicit chairman/risk dashboard context before allowing fixed chairman reference templates.
|
|
312
|
+
* @param block - Rendered customCanvas container.
|
|
313
|
+
* @param data - Custom canvas renderer data.
|
|
314
|
+
* @returns True when parent or nested text indicates the chairman risk cockpit scene.
|
|
315
|
+
*/
|
|
316
|
+
function referenceCompositeLooksLikeChairmanRiskContext(block: WorkbenchBlock, data: CustomCanvasData): boolean {
|
|
317
|
+
return referenceCompositeTextHasChairmanRiskContext(referenceCompositeSearchText(block, data));
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Detects chairman-risk context from only the parent container and OCR text, excluding nested carry-over cards.
|
|
322
|
+
* @param block - Rendered customCanvas container.
|
|
323
|
+
* @param data - Custom canvas renderer data.
|
|
324
|
+
* @returns True when the direct card identity is the chairman risk overview.
|
|
325
|
+
*/
|
|
326
|
+
function referenceCompositeLooksLikeChairmanRiskDirectContext(block: WorkbenchBlock, data: CustomCanvasData): boolean {
|
|
327
|
+
const record = data as unknown as Record<string, unknown>;
|
|
328
|
+
const elements = Array.isArray(data.elements) ? data.elements : [];
|
|
329
|
+
const text = [
|
|
330
|
+
block.title,
|
|
331
|
+
block.subtitle,
|
|
332
|
+
record.title,
|
|
333
|
+
record.subtitle,
|
|
334
|
+
data.narrative,
|
|
335
|
+
data.sourceLabel,
|
|
336
|
+
...elements.map(customCanvasTextElementValue),
|
|
337
|
+
].map((value) => textValue(value)).filter(Boolean).join(' ');
|
|
338
|
+
return referenceCompositeTextHasChairmanRiskContext(text);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Checks whether text contains chairman-risk-specific terms instead of generic operation dashboard words.
|
|
343
|
+
* @param text - Searchable parent and child text.
|
|
344
|
+
* @returns True when fixed chairman risk templates are safe to apply.
|
|
345
|
+
*/
|
|
346
|
+
function referenceCompositeTextHasChairmanRiskContext(text: string): boolean {
|
|
347
|
+
return /董事长|高管|集团经营健康综合得分|GLOBAL RISK POSTURE|TODAY MOVEMENT|重大经营风险|预算严重偏差|资金类预警|风险全景下钻|亏损主体|组织隐患|利润底线|财务资金风险|风险红线|重大投资风险|战略投资追加|chairman|executive|risk posture/i.test(text);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Detects HR dashboard context before allowing fixed HR reference templates.
|
|
352
|
+
* @param block - Rendered customCanvas container.
|
|
353
|
+
* @param data - Custom canvas renderer data.
|
|
354
|
+
* @returns True when the parent or nested text indicates an HR workbench scene.
|
|
355
|
+
*/
|
|
356
|
+
function referenceCompositeLooksLikeHrContext(block: WorkbenchBlock, data: CustomCanvasData): boolean {
|
|
357
|
+
return customCanvasTextLooksLikeHrOrOrgRiskContext(referenceCompositeSearchText(block, data));
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Checks whether a screenshot section belongs to marketing/customer/channel business matrix scenes.
|
|
362
|
+
* @param text - Searchable parent and child text.
|
|
363
|
+
* @returns True when the mixed metric/chart/list template is safe to apply.
|
|
364
|
+
*/
|
|
365
|
+
function customCanvasTextHasBusinessMetricMatrixContext(text: string): boolean {
|
|
366
|
+
return /营销|销售|客户|渠道|投放|业绩|市场|竞品|活动|线索|转化|复购|回款|ROI|CAC|声量|曝光|推广|campaign|sales|marketing|customer|channel|funnel|conversion/i.test(text);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Checks whether a screenshot section is an HR or organization-risk panel that only happens to share metric/chart/list shape.
|
|
371
|
+
* @param text - Searchable parent and child text.
|
|
372
|
+
* @returns True when marketing metric-matrix fixed copy must be suppressed.
|
|
373
|
+
*/
|
|
374
|
+
function customCanvasTextLooksLikeHrOrOrgRiskContext(text: string): boolean {
|
|
375
|
+
return /人力|人事|人才|用工|劳动|社保|合同|考勤|加班|迟到|旷工|请假|薪酬|绩效|招聘|员工|组织|编制|司龄|任免|继任|培训|持证|人效|流失|超编|合规管控|用工合规|HR|CHRO|human resources|workforce|staffing|headcount/i.test(text);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Checks whether a dense screenshot panel belongs to HR salary/cost instead of operation efficiency.
|
|
380
|
+
* @param block - Rendered customCanvas container.
|
|
381
|
+
* @param data - Custom canvas renderer data.
|
|
382
|
+
* @returns True when 人数、薪酬、or 人效排行 semantics should keep the panel on normal nested rendering.
|
|
383
|
+
*/
|
|
384
|
+
function referenceCompositeLooksLikeHrPeopleCostContext(block: WorkbenchBlock, data: CustomCanvasData): boolean {
|
|
385
|
+
const text = referenceCompositeSearchText(block, data);
|
|
386
|
+
if (!customCanvasTextLooksLikeHrOrOrgRiskContext(text)) return false;
|
|
387
|
+
return /人数\s*&\s*薪酬成本|人数.*薪酬|薪酬成本|薪酬结构|人力总成本|人效排行|外包成本执行率|成本趋势|福利|社保|奖金|预算管控|headcount.*cost|salary|compensation/i.test(text);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Returns the source-like chip shown on a reference composite panel header.
|
|
392
|
+
* @param kind - Reference composite family.
|
|
393
|
+
* @returns Compact right-side chip text.
|
|
394
|
+
*/
|
|
395
|
+
function referenceCompositeHeaderChip(kind: ReferenceCompositeKind): string {
|
|
396
|
+
const chipMap: Partial<Record<Exclude<ReferenceCompositeKind, ''>, string>> = {
|
|
397
|
+
ops: '截图还原',
|
|
398
|
+
security: '截图还原',
|
|
399
|
+
asset: '截图还原',
|
|
400
|
+
project: '二级页',
|
|
401
|
+
riskSummary: '集团总览',
|
|
402
|
+
healthRadar: '点击维度穿透专项风险',
|
|
403
|
+
deviation: '目标 VS 实际 · 柱线组合',
|
|
404
|
+
financeRisk: '面积趋势 + 红线锚点',
|
|
405
|
+
expenseRisk: '仅高亮超支 TOP 项',
|
|
406
|
+
deviationInsight: '截图还原',
|
|
407
|
+
organizationRisk: '隐性风险压缩呈现',
|
|
408
|
+
investmentRisk: '极简甘特缩略',
|
|
409
|
+
executiveTodo: '一级',
|
|
410
|
+
shortcutDrill: '二级页',
|
|
411
|
+
quickWorkbench: '实时入口',
|
|
412
|
+
strategyKpi: '经营看板',
|
|
413
|
+
operationHealth: '经营健康',
|
|
414
|
+
operationEfficiency: '运营效率',
|
|
415
|
+
businessMetricMatrix: '指标矩阵',
|
|
416
|
+
hrOrganization: '编制结构',
|
|
417
|
+
hrRiskCompliance: '用工风险',
|
|
418
|
+
hrPeopleCost: '薪酬成本',
|
|
419
|
+
hrTalentTodo: '人才待办',
|
|
420
|
+
};
|
|
421
|
+
if (kind === 'bidCollaboration') return '标案协同';
|
|
422
|
+
return kind ? chipMap[kind] ?? '' : '';
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Checks whether a dense customCanvas panel is a generic business metric matrix.
|
|
427
|
+
* @param block - Rendered customCanvas container.
|
|
428
|
+
* @param data - Custom canvas renderer data.
|
|
429
|
+
* @returns True when mixed metric, chart, and list children should share one high-density template.
|
|
430
|
+
*/
|
|
431
|
+
function customCanvasLooksLikeBusinessMetricMatrix(block: WorkbenchBlock, data: CustomCanvasData): boolean {
|
|
432
|
+
if (!imageComposeCompactCard(block) || customCanvasLooksLikePageHeader(block, data)) return false;
|
|
433
|
+
const nestedBlocks = Array.isArray(data.nestedBlocks) ? data.nestedBlocks : [];
|
|
434
|
+
if (nestedBlocks.length < 4) return false;
|
|
435
|
+
const text = referenceCompositeSearchText(block, data);
|
|
436
|
+
if (!customCanvasTextHasBusinessMetricMatrixContext(text)) return false;
|
|
437
|
+
if (customCanvasTextLooksLikeHrOrOrgRiskContext(text)) return false;
|
|
438
|
+
if (referenceCompositeTextHasItContext(text) || referenceCompositeTextHasChairmanRiskContext(text)) return false;
|
|
439
|
+
if (/快捷工作台|快捷入口|入口导航|待办入口|常用报表|系统入口|战略\s*KPI|KPI\s*看板|经营健康度|运营效率/i.test(text)) return false;
|
|
440
|
+
if (/安全风险|合规治理|基础设施|运维稳定|资源负载|故障.*告警|项目风险|重大投资|董事长|GLOBAL RISK POSTURE|TODAY MOVEMENT/i.test(text)) return false;
|
|
441
|
+
const visualKinds = nestedBlocks.map((nestedBlock) => nestedBlockVisualKind(nestedBlock));
|
|
442
|
+
const previewKinds = nestedBlocks.map((nestedBlock) => nestedBlockPreviewKind(nestedBlock));
|
|
443
|
+
const metricLike = visualKinds.filter((kind) => kind === 'metric' || kind === 'todoGrid' || kind === 'progressList' || kind === 'summary').length
|
|
444
|
+
+ previewKinds.filter((kind) => kind === 'metric' || kind === 'summary').length;
|
|
445
|
+
const chartLike = visualKinds.filter((kind) => kind === 'chart' || kind === 'resourceBars' || kind === 'donut').length
|
|
446
|
+
+ previewKinds.filter((kind) => kind === 'chart').length;
|
|
447
|
+
const listLike = visualKinds.filter((kind) => kind === 'list' || kind === 'simpleList' || kind === 'incidentList' || kind === 'quickLinks').length
|
|
448
|
+
+ previewKinds.filter((kind) => kind === 'list' || kind === 'table').length;
|
|
449
|
+
const usefulCount = metricLike + chartLike + listLike;
|
|
450
|
+
return usefulCount >= Math.max(4, Math.ceil(nestedBlocks.length * 0.72))
|
|
451
|
+
&& metricLike >= 2
|
|
452
|
+
&& (chartLike >= 1 || listLike >= 1);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Detects bid-collaboration role workbench screenshots.
|
|
457
|
+
* @param block - Rendered customCanvas container.
|
|
458
|
+
* @param data - Custom canvas renderer data.
|
|
459
|
+
* @returns True when the parent or nested OCR text belongs to the bid-collaboration family.
|
|
460
|
+
*/
|
|
461
|
+
function customCanvasLooksLikeBidCollaboration(block: WorkbenchBlock, data: CustomCanvasData): boolean {
|
|
462
|
+
if (!imageComposeCompactCard(block) || customCanvasLooksLikePageHeader(block, data)) return false;
|
|
463
|
+
if (customCanvasLooksLikeStandaloneQuickLinks(block, data)) return false;
|
|
464
|
+
const nestedBlocks = Array.isArray(data.nestedBlocks) ? data.nestedBlocks : [];
|
|
465
|
+
if (nestedBlocks.length < 3) return false;
|
|
466
|
+
return referenceCompositeTextHasBidCollaborationPageContext(referenceCompositeSearchText(block, data));
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Detects quick-entry strips that should stay as standalone screenshot cards.
|
|
471
|
+
* @param block - Rendered customCanvas container.
|
|
472
|
+
* @param data - Custom canvas renderer data.
|
|
473
|
+
* @returns True when bid-workbench actions are only shortcut links, not a composite role dashboard.
|
|
474
|
+
*/
|
|
475
|
+
function customCanvasLooksLikeStandaloneQuickLinks(block: WorkbenchBlock, data: CustomCanvasData): boolean {
|
|
476
|
+
const record = data as unknown as Record<string, unknown>;
|
|
477
|
+
const meta = (block.meta && typeof block.meta === 'object' && !Array.isArray(block.meta)
|
|
478
|
+
? block.meta
|
|
479
|
+
: {}) as Record<string, unknown>;
|
|
480
|
+
const capabilityId = textValue(meta.capabilityId, textValue(block.source?.resourceKey));
|
|
481
|
+
const visualKind = textValue(record.visualKind);
|
|
482
|
+
const directText = [
|
|
483
|
+
block.title,
|
|
484
|
+
block.subtitle,
|
|
485
|
+
record.title,
|
|
486
|
+
record.subtitle,
|
|
487
|
+
data.sourceLabel,
|
|
488
|
+
data.narrative,
|
|
489
|
+
].map((value) => textValue(value)).filter(Boolean).join(' ');
|
|
490
|
+
return capabilityId === 'card.composite.bidCollaboration.actions'
|
|
491
|
+
|| visualKind === 'quickLinks'
|
|
492
|
+
|| /快捷入口|快速入口|入口导航|常用入口|quick\s*links?|quick\s*entry/i.test(directText);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Checks whether text belongs to the bid-collaboration workbench family.
|
|
497
|
+
* @param text - Searchable parent and child text.
|
|
498
|
+
* @returns True for bid, production, procurement, logistics, warehouse, or finance role panels.
|
|
499
|
+
*/
|
|
500
|
+
function referenceCompositeTextHasBidCollaborationContext(text: string): boolean {
|
|
501
|
+
if (referenceCompositeTextLooksLikeOrdinaryFinanceDashboard(text)) return false;
|
|
502
|
+
return /标案|投标|经理工作台|目标标案|供应结论|投标结论|产能|工单|齐套|物料|采购|供应商|交期|订单|物流|运输路线|承运商|仓储|库存|库位|出库|发运|备货资金|加急物流|财务预算|销售经理|生产经理|采购经理|物流经理|仓储经理|财务经理|bid|tender|procurement|supplier|logistics|warehouse|inventory|capacity|finance|缁忕悊宸ヤ綔鍙|鏍囨|鎶曟爣|渚涘簲|浜ц兘|宸ュ崟|鐗╂枡|閲囪喘|渚涘簲鍟|浜ゆ湡|璁㈠崟|杩愯緭|鎵胯繍|浠撳偍|搴撳瓨|搴撲綅|鍑哄簱|鍙戣繍|澶囪揣|璐㈠姟|棰勭畻/i.test(text);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Checks whether bid text describes a full role workbench instead of a local business module.
|
|
507
|
+
* @param text - Searchable parent and child text.
|
|
508
|
+
* @returns True when the text has both bid-domain terms and page-level workbench/collaboration identity.
|
|
509
|
+
*/
|
|
510
|
+
function referenceCompositeTextHasBidCollaborationPageContext(text: string): boolean {
|
|
511
|
+
if (!referenceCompositeTextHasBidCollaborationContext(text)) return false;
|
|
512
|
+
return /标案协同|投标协同|协同工作台|角色工作台|经理工作台|销售经理工作台|生产经理工作台|采购经理工作台|物流经理工作台|仓储经理工作台|财务经理工作台|全景|总览|驾驶舱|workbench|dashboard|collaboration|缁忕悊宸ヤ綔鍙|鍗忓悓宸ヤ綔鍙|椹鹃┒鑸|鎬昏/i.test(text);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* Detects plain finance screenshots that only share finance vocabulary with bid templates.
|
|
517
|
+
* @param text - Searchable parent and child text.
|
|
518
|
+
* @returns True when a fixed bid-collaboration template would be a false positive.
|
|
519
|
+
*/
|
|
520
|
+
function referenceCompositeTextLooksLikeOrdinaryFinanceDashboard(text: string): boolean {
|
|
521
|
+
if (/标案|投标|目标标案|bid|tender|鏍囨|鎶曟爣/i.test(text)) return false;
|
|
522
|
+
return /finance|financial|revenue|account|cash|invoice|receivable|payable|expense|profit|margin/i.test(text);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Detects top workbench/page headers so nested child text cannot activate business reference panels.
|
|
527
|
+
* @param block - Rendered customCanvas container.
|
|
528
|
+
* @param data - Custom canvas renderer data.
|
|
529
|
+
* @returns True when the direct container title is page chrome rather than a business section.
|
|
530
|
+
*/
|
|
531
|
+
function customCanvasLooksLikePageHeader(block: WorkbenchBlock, data: CustomCanvasData): boolean {
|
|
532
|
+
const record = data as unknown as Record<string, unknown>;
|
|
533
|
+
if (customCanvasHasExplicitPageHeaderIdentity(block) && !customCanvasLooksLikeRiskSummaryTitle(block)) return true;
|
|
534
|
+
const directText = [
|
|
535
|
+
block.title,
|
|
536
|
+
block.subtitle,
|
|
537
|
+
record.title,
|
|
538
|
+
record.subtitle,
|
|
539
|
+
data.narrative,
|
|
540
|
+
record.sourceLabel,
|
|
541
|
+
].map((value) => textValue(value)).filter(Boolean).join(' ');
|
|
542
|
+
if (!directText) return false;
|
|
543
|
+
const parentKind = referenceCompositeKindFromContainerTitle(block.title);
|
|
544
|
+
if (parentKind && referenceCompositeKindAllowedForBlock(parentKind, block, data)) return false;
|
|
545
|
+
if (customCanvasLooksLikeRiskSummaryTitle(block)) return false;
|
|
546
|
+
return /(^|\s)(CIO|CEO)\b|专属工作台|工作台|驾驶舱|信息化中心|自动巡检|顶部导航|导航栏|标题栏|导航区|页头|页眉|workspace|workbench|cockpit|header|banner/i.test(directText);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* Checks stable metadata for image screenshot page chrome.
|
|
551
|
+
* @param block - Rendered customCanvas container.
|
|
552
|
+
* @returns True when source or V2 metadata explicitly marks a screenshot header.
|
|
553
|
+
*/
|
|
554
|
+
function customCanvasHasExplicitPageHeaderIdentity(block: WorkbenchBlock): boolean {
|
|
555
|
+
const meta = (block.meta && typeof block.meta === 'object' && !Array.isArray(block.meta)
|
|
556
|
+
? block.meta
|
|
557
|
+
: {}) as Record<string, unknown>;
|
|
558
|
+
const metaV2 = (meta.v2 && typeof meta.v2 === 'object' && !Array.isArray(meta.v2)
|
|
559
|
+
? meta.v2
|
|
560
|
+
: {}) as Record<string, unknown>;
|
|
561
|
+
return [
|
|
562
|
+
block.source?.resourceKey,
|
|
563
|
+
meta.capabilityId,
|
|
564
|
+
meta.resourceKey,
|
|
565
|
+
metaV2.capabilityId,
|
|
566
|
+
metaV2.resourceKey,
|
|
567
|
+
].some((value) => typeof value === 'string' && /workbench\.v2\.image\.header|image-header-banner|dark_header/i.test(value));
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* Checks the parent title only for the chairman risk-summary band.
|
|
572
|
+
* @param block - Rendered customCanvas container.
|
|
573
|
+
* @returns True when the container title itself is business risk content, not page chrome.
|
|
574
|
+
*/
|
|
575
|
+
function customCanvasLooksLikeRiskSummaryTitle(block: WorkbenchBlock): boolean {
|
|
576
|
+
return /风险总览|风险概览|顶部风险|集团经营风险总览|集团经营健康综合得分|GLOBAL RISK POSTURE|risk posture/i.test(textValue(block.title));
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* Checks whether an image customCanvas should render with the page-header template.
|
|
581
|
+
* @param block - Rendered customCanvas container.
|
|
582
|
+
* @param data - Custom canvas renderer data.
|
|
583
|
+
* @returns True when the block is top page chrome rather than a normal dashboard card.
|
|
584
|
+
*/
|
|
585
|
+
function customCanvasPageHeaderBlock(block: WorkbenchBlock, data: CustomCanvasData): boolean {
|
|
586
|
+
return customCanvasLooksLikePageHeader(block, data) && !customCanvasRiskSummaryBand(block, data);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Checks whether a page-header block is only structural screenshot chrome.
|
|
591
|
+
* @param block - Rendered customCanvas container.
|
|
592
|
+
* @param data - Custom canvas renderer data.
|
|
593
|
+
* @returns True when there is no OCR/nested/narrative content to paint.
|
|
594
|
+
*/
|
|
595
|
+
function customCanvasEmptyPageHeaderPlaceholder(block: WorkbenchBlock, data: CustomCanvasData): boolean {
|
|
596
|
+
if (!customCanvasPageHeaderBlock(block, data)) return false;
|
|
597
|
+
if (customCanvasHeaderHasRenderableContent(block, data)) return false;
|
|
598
|
+
return !customCanvasHasNestedBlocks(data)
|
|
599
|
+
&& customCanvasVisibleElements(block, data).length === 0
|
|
600
|
+
&& !customCanvasVisibleNarrative(block, data);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Checks whether a screenshot page header carries enough content or appearance metadata to paint.
|
|
605
|
+
* @param block - Rendered customCanvas container.
|
|
606
|
+
* @param data - Custom canvas renderer data.
|
|
607
|
+
* @returns True when the header should render chrome instead of a transparent placeholder.
|
|
608
|
+
*/
|
|
609
|
+
function customCanvasHeaderHasRenderableContent(block: WorkbenchBlock, data: CustomCanvasData): boolean {
|
|
610
|
+
if (!customCanvasPageHeaderBlock(block, data)) return false;
|
|
611
|
+
if (customCanvasHeaderTitle(block, data)) return true;
|
|
612
|
+
if (customCanvasHeaderSubtitle(block, data)) return true;
|
|
613
|
+
if (customCanvasHeaderPills(block, data).length > 0) return true;
|
|
614
|
+
const visual = visualFor(block);
|
|
615
|
+
const record = data as unknown as Record<string, unknown>;
|
|
616
|
+
const appearance = (isRecord(record.appearance) ? record.appearance : {}) as Record<string, unknown>;
|
|
617
|
+
return [
|
|
618
|
+
data.background,
|
|
619
|
+
record.backgroundColor,
|
|
620
|
+
record.textColor,
|
|
621
|
+
record.borderColor,
|
|
622
|
+
record.themeId,
|
|
623
|
+
visual.backgroundColor,
|
|
624
|
+
visual.textColor,
|
|
625
|
+
visual.borderColor,
|
|
626
|
+
visual.themeId,
|
|
627
|
+
appearance.background,
|
|
628
|
+
appearance.backgroundColor,
|
|
629
|
+
appearance.textColor,
|
|
630
|
+
appearance.borderColor,
|
|
631
|
+
appearance.themeId,
|
|
632
|
+
].some((value) => Boolean(textValue(value)));
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Checks whether a customCanvas image container has no recognized body but should still reserve a compact visual placeholder.
|
|
637
|
+
* @param block - Rendered customCanvas container.
|
|
638
|
+
* @param data - Custom canvas renderer data.
|
|
639
|
+
* @returns True when the generic title-only rendering would look like a blank card.
|
|
640
|
+
*/
|
|
641
|
+
function customCanvasEmptyImagePlaceholder(block: WorkbenchBlock, data: CustomCanvasData): boolean {
|
|
642
|
+
if (!imageComposeCompactCard(block)) return false;
|
|
643
|
+
if (customCanvasPageHeaderBlock(block, data) || customCanvasRiskSummaryBand(block, data)) return false;
|
|
644
|
+
return !customCanvasHasNestedBlocks(data)
|
|
645
|
+
&& customCanvasVisibleElements(block, data).length === 0
|
|
646
|
+
&& !customCanvasVisibleNarrative(block, data);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Checks whether a compact customCanvas container should render as the dark top-row alert list.
|
|
651
|
+
* @param block - Rendered customCanvas container.
|
|
652
|
+
* @param data - Custom canvas renderer data.
|
|
653
|
+
* @returns True for fault/alert leaf containers with a small set of incident children.
|
|
654
|
+
*/
|
|
655
|
+
function customCanvasAlertLeafContainer(block: WorkbenchBlock, data: CustomCanvasData): boolean {
|
|
656
|
+
if (!imageComposeCompactCard(block) || customCanvasPageHeaderBlock(block, data) || customCanvasRiskSummaryBand(block, data)) return false;
|
|
657
|
+
if (customCanvasReferenceCompositeKind(block, data)) return false;
|
|
658
|
+
const nestedBlocks = Array.isArray(data.nestedBlocks) ? data.nestedBlocks : [];
|
|
659
|
+
if (nestedBlocks.length === 0 || nestedBlocks.length > 4) return false;
|
|
660
|
+
const incidentText = [block.title, block.subtitle, data.narrative, ...nestedBlocks.map((nestedBlock) => nestedBlock.title)].join(' ');
|
|
661
|
+
const hasIncidentVisualKind = nestedBlocks.some((nestedBlock) => nestedBlockVisualKind(nestedBlock) === 'incidentList');
|
|
662
|
+
const hasIncidentText = /故障|告警|红警|置顶|incident|alert|alarm|fault/i.test(incidentText);
|
|
663
|
+
// Tone labels and P-level badges also appear on business risk/opportunity cards; require incident identity.
|
|
664
|
+
return hasIncidentVisualKind && hasIncidentText;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Returns incident rows for an alert leaf customCanvas container.
|
|
669
|
+
* @param data - Custom canvas renderer data.
|
|
670
|
+
* @returns Rows derived from nested child cards, falling back to CIO reference incidents.
|
|
671
|
+
*/
|
|
672
|
+
function customCanvasAlertLeafItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
673
|
+
const nestedBlocks = Array.isArray(data.nestedBlocks) ? data.nestedBlocks : [];
|
|
674
|
+
const rows = nestedBlocks.map((nestedBlock, index) => {
|
|
675
|
+
const dataRecord = (isRecord(nestedBlock.data) ? nestedBlock.data : {}) as Record<string, unknown>;
|
|
676
|
+
const value = nestedBlockMetricValue(nestedBlock);
|
|
677
|
+
return {
|
|
678
|
+
title: textValue(nestedBlock.title, imageComposeAlertRankingTitle({}, index)),
|
|
679
|
+
severity: /^P[12]$/i.test(value) ? value.toUpperCase() : textValue(dataRecord.severity, textValue(dataRecord.level, index >= 2 ? 'P2' : 'P1')),
|
|
680
|
+
time: textValue(dataRecord.time, ['08:42', '09:05', '09:18'][index] ?? ''),
|
|
681
|
+
tone: index >= 2 ? 'warning' : 'critical',
|
|
682
|
+
};
|
|
683
|
+
});
|
|
684
|
+
const filledRows = customCanvasAlertLeafFilledItems(data, rows);
|
|
685
|
+
if (filledRows.length > 0) return filledRows;
|
|
686
|
+
return rows.length > 0 ? rows : [
|
|
687
|
+
{ severity: 'P1', title: 'MES 接口响应异常,影响生产报工', time: '08:42', tone: 'critical' },
|
|
688
|
+
{ severity: 'P1', title: '核心数据库慢查询升高,已派单 DBA', time: '09:05', tone: 'critical' },
|
|
689
|
+
{ severity: 'P2', title: '华东云资源存储水位 84%', time: '09:18', tone: 'warning' },
|
|
690
|
+
];
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* Fills sparse dark alert panels so one or two OCR children do not leave a large blank band.
|
|
695
|
+
* @param data - Custom canvas renderer data.
|
|
696
|
+
* @param rows - Alert rows derived from recognized nested children.
|
|
697
|
+
* @returns Enough alert rows for the three-row screenshot panel.
|
|
698
|
+
*/
|
|
699
|
+
function customCanvasAlertLeafFilledItems(
|
|
700
|
+
data: CustomCanvasData,
|
|
701
|
+
rows: Array<Record<string, unknown>>,
|
|
702
|
+
): Array<Record<string, unknown>> {
|
|
703
|
+
const usableRows = rows.filter((row) => imageComposeAlertRankingTitle(row, 0));
|
|
704
|
+
if (usableRows.length >= 3) return usableRows.slice(0, 3);
|
|
705
|
+
const fallbackRows = customCanvasAlertLeafFallbackItems(data);
|
|
706
|
+
const existingTitles = new Set(usableRows.map((row, index) => imageComposeAlertRankingTitle(row, index)));
|
|
707
|
+
const fillers = fallbackRows.filter((row, index) => !existingTitles.has(imageComposeAlertRankingTitle(row, index)));
|
|
708
|
+
return [...usableRows, ...fillers].slice(0, 3);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* Builds screenshot-density fallback rows for sparse dark alert panels.
|
|
713
|
+
* @param data - Custom canvas renderer data used for domain hints.
|
|
714
|
+
* @returns Cost/risk or incident fallback rows.
|
|
715
|
+
*/
|
|
716
|
+
function customCanvasAlertLeafFallbackItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
717
|
+
const nestedBlocks = Array.isArray(data.nestedBlocks) ? data.nestedBlocks : [];
|
|
718
|
+
const dataRecord = data as unknown as Record<string, unknown>;
|
|
719
|
+
const text = [
|
|
720
|
+
dataRecord.title,
|
|
721
|
+
data.narrative,
|
|
722
|
+
...nestedBlocks.flatMap((nestedBlock) => [
|
|
723
|
+
nestedBlock.title,
|
|
724
|
+
nestedBlockClassifierText(nestedBlock),
|
|
725
|
+
nestedBlockDataSummary(nestedBlock),
|
|
726
|
+
]),
|
|
727
|
+
].join(' ');
|
|
728
|
+
if (/\u6210\u672c|\u8d39\u7528|\u8d85\u652f|\u9884\u7b97|cost|expense|budget/i.test(text)) {
|
|
729
|
+
return [
|
|
730
|
+
{ severity: 'P1', title: '成本 & 费用超支监控 · 柱状图', time: '08:42', tone: 'critical' },
|
|
731
|
+
{ severity: 'P1', title: '3项超阈值', time: '09:05', tone: 'critical' },
|
|
732
|
+
{ severity: 'P2', title: '冻结审计与费用复核待处理', time: '09:18', tone: 'warning' },
|
|
733
|
+
];
|
|
734
|
+
}
|
|
735
|
+
return [
|
|
736
|
+
{ severity: 'P1', title: 'MES interface abnormal response', time: '08:42', tone: 'critical' },
|
|
737
|
+
{ severity: 'P1', title: 'Core database slow query rising', time: '09:05', tone: 'critical' },
|
|
738
|
+
{ severity: 'P2', title: 'Cloud storage watermark at 84%', time: '09:18', tone: 'warning' },
|
|
739
|
+
];
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
/**
|
|
743
|
+
* Returns the main page-header title from block and renderer data.
|
|
744
|
+
* @param block - Rendered customCanvas container.
|
|
745
|
+
* @param data - Custom canvas renderer data.
|
|
746
|
+
* @returns Header title text.
|
|
747
|
+
*/
|
|
748
|
+
function customCanvasHeaderTitle(block: WorkbenchBlock, data: CustomCanvasData): string {
|
|
749
|
+
const record = data as unknown as Record<string, unknown>;
|
|
750
|
+
return textValue(block.title, textValue(record.title, customCanvasTextElementValue(data.elements?.[0])));
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
/**
|
|
754
|
+
* Returns the page-header subtitle from explicit subtitle, narrative, or OCR text.
|
|
755
|
+
* @param block - Rendered customCanvas container.
|
|
756
|
+
* @param data - Custom canvas renderer data.
|
|
757
|
+
* @returns Header subtitle text.
|
|
758
|
+
*/
|
|
759
|
+
function customCanvasHeaderSubtitle(block: WorkbenchBlock, data: CustomCanvasData): string {
|
|
760
|
+
const record = data as unknown as Record<string, unknown>;
|
|
761
|
+
const explicitSubtitle = textValue(block.subtitle, textValue(record.subtitle));
|
|
762
|
+
if (explicitSubtitle) return explicitSubtitle;
|
|
763
|
+
const narrative = customCanvasVisibleNarrative(block, data);
|
|
764
|
+
if (narrative) return narrative;
|
|
765
|
+
return customCanvasTextElementValue(data.elements?.find((element) => /subtitle/i.test(textValue(element.id))));
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
/**
|
|
769
|
+
* Returns a compact logo label for image-composed page headers.
|
|
770
|
+
* @param block - Rendered customCanvas container.
|
|
771
|
+
* @param data - Custom canvas renderer data.
|
|
772
|
+
* @returns Short OCR/title-derived logo text.
|
|
773
|
+
*/
|
|
774
|
+
function customCanvasHeaderLogo(block: WorkbenchBlock, data: CustomCanvasData): string {
|
|
775
|
+
const elementText = (Array.isArray(data.elements) ? data.elements : [])
|
|
776
|
+
.map(customCanvasTextElementValue)
|
|
777
|
+
.filter(Boolean)
|
|
778
|
+
.join(' ');
|
|
779
|
+
const headerText = [
|
|
780
|
+
elementText,
|
|
781
|
+
customCanvasHeaderTitle(block, data),
|
|
782
|
+
customCanvasHeaderSubtitle(block, data),
|
|
783
|
+
block.title,
|
|
784
|
+
].filter(Boolean).join(' ');
|
|
785
|
+
const roleMatch = headerText.match(/\b(CIO|CEO|COO|CFO|CTO)\b/i);
|
|
786
|
+
if (roleMatch?.[1]) return roleMatch[1].toUpperCase();
|
|
787
|
+
if (/董事长|董事会/.test(headerText)) return '董';
|
|
788
|
+
if (/销售经理|销售/.test(headerText)) return '销';
|
|
789
|
+
if (/生产经理|生产/.test(headerText)) return '产';
|
|
790
|
+
if (/采购经理|采购/.test(headerText)) return '采';
|
|
791
|
+
if (/物流经理|物流/.test(headerText)) return '物';
|
|
792
|
+
if (/仓储经理|仓储/.test(headerText)) return '仓';
|
|
793
|
+
if (/财务经理|财务/.test(headerText)) return '财';
|
|
794
|
+
const chineseTitle = customCanvasHeaderTitle(block, data).trim();
|
|
795
|
+
return chineseTitle ? chineseTitle.slice(0, 1) : '台';
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
/**
|
|
799
|
+
* Builds scenario-specific logo colors for image-composed page headers.
|
|
800
|
+
* @param block - Rendered customCanvas container.
|
|
801
|
+
* @param data - Custom canvas renderer data.
|
|
802
|
+
* @returns Inline style for the compact logo block.
|
|
803
|
+
*/
|
|
804
|
+
function customCanvasHeaderLogoStyle(block: WorkbenchBlock, data: CustomCanvasData): CSSProperties {
|
|
805
|
+
const headerText = [
|
|
806
|
+
customCanvasHeaderTitle(block, data),
|
|
807
|
+
customCanvasHeaderSubtitle(block, data),
|
|
808
|
+
block.title,
|
|
809
|
+
].filter(Boolean).join(' ');
|
|
810
|
+
if (/董事长|董事会|风险预警|经营偏差/.test(headerText)) {
|
|
811
|
+
return {
|
|
812
|
+
background: '#7b1930',
|
|
813
|
+
color: '#ffffff',
|
|
814
|
+
boxShadow: '0 8px 16px rgba(123,25,48,0.18)',
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
if (customCanvasPageHeaderDark(block, data)) {
|
|
818
|
+
return {
|
|
819
|
+
background: 'rgba(255,255,255,0.18)',
|
|
820
|
+
border: '1px solid rgba(255,255,255,0.24)',
|
|
821
|
+
color: '#ffffff',
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
if (textValue(visualFor(block).themeId) === 'image-header-banner') {
|
|
825
|
+
return {
|
|
826
|
+
background: '#ffffff',
|
|
827
|
+
border: '1px solid #eef1f7',
|
|
828
|
+
color: '#3426d9',
|
|
829
|
+
};
|
|
830
|
+
}
|
|
831
|
+
return {
|
|
832
|
+
background: '#4C78FC',
|
|
833
|
+
color: '#ffffff',
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
/**
|
|
838
|
+
* Checks whether a concatenated page-header style bundle carries a dark source background.
|
|
839
|
+
* @param candidates - Page-header visual and OCR candidates.
|
|
840
|
+
* @returns True when the source background should render as dark chrome.
|
|
841
|
+
*/
|
|
842
|
+
function isDarkPageHeaderBackground(candidates: string): boolean {
|
|
843
|
+
return /(#)?(0f172a|111827|141414|1f2937|172235|1e293b)/i.test(candidates.replace(/\s+/g, ''));
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
/**
|
|
847
|
+
* Checks whether an image-composed page header should use dark screenshot chrome.
|
|
848
|
+
* @param block - Rendered customCanvas container.
|
|
849
|
+
* @param data - Custom canvas renderer data.
|
|
850
|
+
* @returns True when metadata, OCR, or title implies a dark top banner.
|
|
851
|
+
*/
|
|
852
|
+
function customCanvasPageHeaderDark(block: WorkbenchBlock, data: CustomCanvasData): boolean {
|
|
853
|
+
if (customCanvasEmptyPageHeaderPlaceholder(block, data)) return false;
|
|
854
|
+
const record = data as unknown as Record<string, unknown>;
|
|
855
|
+
const visual = visualFor(block);
|
|
856
|
+
const appearance = (isRecord(record.appearance) ? record.appearance : {}) as Record<string, unknown>;
|
|
857
|
+
const candidates = [
|
|
858
|
+
data.background,
|
|
859
|
+
record.backgroundColor,
|
|
860
|
+
appearance.backgroundColor,
|
|
861
|
+
visual.backgroundColor,
|
|
862
|
+
visual.borderColor,
|
|
863
|
+
appearance.themeId,
|
|
864
|
+
visual.themeId,
|
|
865
|
+
customCanvasHeaderTitle(block, data),
|
|
866
|
+
customCanvasHeaderSubtitle(block, data),
|
|
867
|
+
].map((value) => textValue(value)).filter(Boolean).join(' ');
|
|
868
|
+
if (/dark_header|dark\b|深色|夜间/i.test(candidates) && !/image-header-banner/i.test(candidates)) return true;
|
|
869
|
+
return isDarkPageHeaderBackground(candidates);
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
/**
|
|
873
|
+
* Builds the dedicated page-header visual style from screenshot metadata.
|
|
874
|
+
* @param block - Rendered customCanvas container.
|
|
875
|
+
* @param data - Custom canvas renderer data.
|
|
876
|
+
* @returns Inline CSS for dark/light header chrome.
|
|
877
|
+
*/
|
|
878
|
+
function customCanvasPageHeaderStyle(block: WorkbenchBlock, data: CustomCanvasData): CSSProperties {
|
|
879
|
+
if (customCanvasEmptyPageHeaderPlaceholder(block, data)) {
|
|
880
|
+
return {
|
|
881
|
+
background: 'transparent',
|
|
882
|
+
borderColor: 'transparent',
|
|
883
|
+
color: 'transparent',
|
|
884
|
+
boxShadow: 'none',
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
const visual = visualFor(block);
|
|
888
|
+
const record = data as unknown as Record<string, unknown>;
|
|
889
|
+
const appearance = (isRecord(record.appearance) ? record.appearance : {}) as Record<string, unknown>;
|
|
890
|
+
const imageHeaderBackground = textValue(
|
|
891
|
+
record.backgroundColor,
|
|
892
|
+
textValue(
|
|
893
|
+
data.background,
|
|
894
|
+
textValue(appearance.backgroundColor, textValue(visual.backgroundColor)),
|
|
895
|
+
),
|
|
896
|
+
);
|
|
897
|
+
const imageHeaderThemeId = textValue(appearance.themeId, textValue(visual.themeId));
|
|
898
|
+
if (imageHeaderThemeId === 'image-header-banner' && imageHeaderBackground && customCanvasPageHeaderDark(block, data)) {
|
|
899
|
+
return {
|
|
900
|
+
background: imageHeaderBackground,
|
|
901
|
+
borderColor: imageHeaderBackground,
|
|
902
|
+
color: textValue(appearance.textColor, textValue(visual.textColor, '#f8fafc')),
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
if (customCanvasPageHeaderDark(block, data)) {
|
|
906
|
+
return {
|
|
907
|
+
background: '#111827',
|
|
908
|
+
borderColor: '#1e293b',
|
|
909
|
+
color: '#f8fafc',
|
|
910
|
+
};
|
|
911
|
+
}
|
|
912
|
+
return {
|
|
913
|
+
background: 'rgba(248,250,252,0.72)',
|
|
914
|
+
borderColor: 'transparent',
|
|
915
|
+
color: '#0f172a',
|
|
916
|
+
boxShadow: 'none',
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
/**
|
|
921
|
+
* Returns page-header text classes for dark/light variants.
|
|
922
|
+
* @param block - Rendered customCanvas container.
|
|
923
|
+
* @param data - Custom canvas renderer data.
|
|
924
|
+
* @param tone - Header text role.
|
|
925
|
+
* @returns Tailwind class string.
|
|
926
|
+
*/
|
|
927
|
+
function customCanvasPageHeaderTextClass(block: WorkbenchBlock, data: CustomCanvasData, tone: 'title' | 'subtitle' | 'pill'): string {
|
|
928
|
+
const dark = customCanvasPageHeaderDark(block, data);
|
|
929
|
+
if (tone === 'title') return dark ? 'text-slate-50' : 'text-slate-950';
|
|
930
|
+
if (tone === 'subtitle') return dark ? 'text-slate-300' : 'text-slate-500';
|
|
931
|
+
return dark
|
|
932
|
+
? 'border-white/20 bg-white/10 text-slate-50'
|
|
933
|
+
: 'border-slate-200 bg-white text-slate-700';
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
/**
|
|
937
|
+
* Reads display text from a customCanvas element.
|
|
938
|
+
* @param element - Candidate OCR element.
|
|
939
|
+
* @returns Combined label/value text.
|
|
940
|
+
*/
|
|
941
|
+
function customCanvasTextElementValue(element: CustomCanvasData['elements'][number] | undefined): string {
|
|
942
|
+
if (!element) return '';
|
|
943
|
+
return [element.label, element.value].map((value) => textValue(value)).filter(Boolean).join(' ');
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
/**
|
|
947
|
+
* Checks whether a customCanvas OCR element repeats the header title or subtitle.
|
|
948
|
+
* @param element - Candidate OCR element.
|
|
949
|
+
* @param block - Rendered customCanvas container.
|
|
950
|
+
* @param data - Custom canvas renderer data.
|
|
951
|
+
* @returns True when the element should be consumed by the header template, not shown as a pill.
|
|
952
|
+
*/
|
|
953
|
+
function customCanvasHeaderRepeatingElement(element: CustomCanvasData['elements'][number], block: WorkbenchBlock, data: CustomCanvasData): boolean {
|
|
954
|
+
const value = customCanvasTextElementValue(element);
|
|
955
|
+
if (!value) return true;
|
|
956
|
+
return value === customCanvasHeaderTitle(block, data) || value === customCanvasHeaderSubtitle(block, data);
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
/**
|
|
960
|
+
* Returns compact right-side page-header pills from model-recognized OCR text.
|
|
961
|
+
* @param block - Rendered customCanvas container.
|
|
962
|
+
* @param data - Custom canvas renderer data.
|
|
963
|
+
* @returns Header status/filter/date pill text in visual order.
|
|
964
|
+
*/
|
|
965
|
+
function customCanvasHeaderPills(block: WorkbenchBlock, data: CustomCanvasData): string[] {
|
|
966
|
+
const elements = Array.isArray(data.elements) ? data.elements : [];
|
|
967
|
+
return elements
|
|
968
|
+
.filter((element) => !customCanvasGeneratedElement(element))
|
|
969
|
+
.filter((element) => !customCanvasHeaderRepeatingElement(element, block, data))
|
|
970
|
+
.sort((left, right) => {
|
|
971
|
+
const leftX = numberValue(left.x, 0);
|
|
972
|
+
const rightX = numberValue(right.x, 0);
|
|
973
|
+
if (leftX !== rightX) return leftX - rightX;
|
|
974
|
+
return numberValue(left.y, 0) - numberValue(right.y, 0);
|
|
975
|
+
})
|
|
976
|
+
.map(customCanvasTextElementValue)
|
|
977
|
+
.filter(Boolean)
|
|
978
|
+
.slice(0, 4);
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
/**
|
|
982
|
+
* Returns page-header pills with scenario-specific fallbacks used by screenshot headers.
|
|
983
|
+
* @param block - Rendered customCanvas container.
|
|
984
|
+
* @param data - Custom canvas renderer data.
|
|
985
|
+
* @returns Header pills in source-like order.
|
|
986
|
+
*/
|
|
987
|
+
function customCanvasHeaderPillsWithFallback(block: WorkbenchBlock, data: CustomCanvasData): string[] {
|
|
988
|
+
const pills = customCanvasHeaderPills(block, data);
|
|
989
|
+
const headerText = [
|
|
990
|
+
customCanvasHeaderTitle(block, data),
|
|
991
|
+
customCanvasHeaderSubtitle(block, data),
|
|
992
|
+
block.title,
|
|
993
|
+
].join(' ');
|
|
994
|
+
if (/董事长|董事会|风险预警|经营偏差/.test(headerText) && !pills.some((pill) => /集团总览/.test(pill))) {
|
|
995
|
+
return ['集团总览', ...pills].slice(0, 4);
|
|
996
|
+
}
|
|
997
|
+
return pills;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
/**
|
|
1001
|
+
* Classifies a composite panel by the parent section title before child text is considered.
|
|
1002
|
+
* @param title - Visible section title from the image-composed container.
|
|
1003
|
+
* @returns Reference composite family when the title itself is decisive.
|
|
1004
|
+
*/
|
|
1005
|
+
function referenceCompositeKindFromContainerTitle(title: unknown): ReferenceCompositeKind {
|
|
1006
|
+
const text = textValue(title);
|
|
1007
|
+
if (referenceCompositeTextHasBidCollaborationPageContext(text)) return 'bidCollaboration';
|
|
1008
|
+
if (/快捷工作台|快捷入口|入口导航|待办入口|常用报表|系统入口/.test(text)) return 'quickWorkbench';
|
|
1009
|
+
if (/战略\s*KPI|KPI\s*看板|战略KPI看板|经营KPI|核心指标看板/.test(text)) return 'strategyKpi';
|
|
1010
|
+
if (/经营健康度|经营健康|健康度/.test(text)) return 'operationHealth';
|
|
1011
|
+
if (/组织编制|人员结构|编制使用|平均司龄|部门编制|关键异动/.test(text)) return 'hrOrganization';
|
|
1012
|
+
if (/人力风险|用工风险|用工合规|考勤异常|劳动纠纷|合规管控/.test(text)) return 'hrRiskCompliance';
|
|
1013
|
+
if (/人数.*薪酬|薪酬成本|薪酬结构|人力总成本|成本趋势/.test(text)) return 'hrPeopleCost';
|
|
1014
|
+
if (/人才发展|待办中心|人才梯队|继任计划|储备干部|培训完成|人事待办|快捷入口/.test(text)) return 'hrTalentTodo';
|
|
1015
|
+
if (/运营效率|交付|履约|资源利用|重点项目里程碑/.test(text)) return 'operationEfficiency';
|
|
1016
|
+
if (/快捷穿透|风险全景下钻|二级页/.test(text)) return 'shortcutDrill';
|
|
1017
|
+
if (/五大维度|健康雷达|雷达/.test(text)) return 'healthRadar';
|
|
1018
|
+
if (/经营目标偏差|目标完成|目标偏差/.test(text)) return 'deviation';
|
|
1019
|
+
if (/财务资金|资金风险|现金流|逾期应收/.test(text)) return 'financeRisk';
|
|
1020
|
+
if (/偏差洞察|利润同比下滑|预算偏离/.test(text)) return 'deviationInsight';
|
|
1021
|
+
if (/成本.*费用|费用超支|超阈值/.test(text)) return 'expenseRisk';
|
|
1022
|
+
if (/组织.*人效|人效风险|组织稳定/.test(text)) return 'organizationRisk';
|
|
1023
|
+
if (/重大投资|项目风险|投资.*项目/.test(text)) return 'investmentRisk';
|
|
1024
|
+
if (/高管重大待办|董事长督办|重大待办/.test(text)) return 'executiveTodo';
|
|
1025
|
+
if (/数字化|项目|研发|效能/.test(text)) return 'project';
|
|
1026
|
+
if (/资产|成本|License|预算/.test(text)) return 'asset';
|
|
1027
|
+
if (/信息安全|合规治理|安全风险|安全健康/.test(text)) return 'security';
|
|
1028
|
+
if (/基础设施|运维稳定|稳定性|服务监控|资源负载/.test(text)) return 'ops';
|
|
1029
|
+
return '';
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
/**
|
|
1033
|
+
* Builds transparent diagnostic geometry for nested cards represented inside a composite preview.
|
|
1034
|
+
* @param kind - Reference composite family currently rendered.
|
|
1035
|
+
* @param nestedBlock - Nested child card represented by the transparent diagnostic marker.
|
|
1036
|
+
* @param index - Nested card index inside the parent container.
|
|
1037
|
+
* @returns In-parent box style used by browser diagnostics without affecting the visible composite.
|
|
1038
|
+
*/
|
|
1039
|
+
function referenceCompositeDiagnosticStyle(kind: ReferenceCompositeKind, nestedBlock: CustomCanvasNestedBlock, index: number, nestedBlocks: readonly CustomCanvasNestedBlock[] = []): CSSProperties {
|
|
1040
|
+
const riskSummaryRegions = [
|
|
1041
|
+
{ left: '3%', top: '20%', width: '20%', height: '60%' },
|
|
1042
|
+
{ left: '24%', top: '16%', width: '12%', height: '68%' },
|
|
1043
|
+
{ left: '37%', top: '16%', width: '12%', height: '68%' },
|
|
1044
|
+
{ left: '50%', top: '16%', width: '12%', height: '68%' },
|
|
1045
|
+
{ left: '63%', top: '16%', width: '12%', height: '68%' },
|
|
1046
|
+
{ left: '76%', top: '16%', width: '21%', height: '68%' },
|
|
1047
|
+
];
|
|
1048
|
+
const opsRegions = [
|
|
1049
|
+
{ left: '6%', top: '16%', width: '42%', height: '38%' },
|
|
1050
|
+
{ left: '53%', top: '16%', width: '41%', height: '38%' },
|
|
1051
|
+
{ left: '6%', top: '60%', width: '42%', height: '30%' },
|
|
1052
|
+
{ left: '53%', top: '60%', width: '41%', height: '30%' },
|
|
1053
|
+
];
|
|
1054
|
+
const securityRegions = [
|
|
1055
|
+
{ left: '5%', top: '15%', width: '49%', height: '66%' },
|
|
1056
|
+
{ left: '5%', top: '82%', width: '49%', height: '14%' },
|
|
1057
|
+
{ left: '59%', top: '15%', width: '36%', height: '81%' },
|
|
1058
|
+
];
|
|
1059
|
+
const assetRegions = [
|
|
1060
|
+
{ left: '7%', top: '15%', width: '35%', height: '38%' },
|
|
1061
|
+
{ left: '50%', top: '15%', width: '42%', height: '38%' },
|
|
1062
|
+
{ left: '7%', top: '60%', width: '35%', height: '28%' },
|
|
1063
|
+
{ left: '50%', top: '60%', width: '42%', height: '28%' },
|
|
1064
|
+
];
|
|
1065
|
+
const projectRegions = [
|
|
1066
|
+
{ left: '6%', top: '16%', width: '48%', height: '42%' },
|
|
1067
|
+
{ left: '59%', top: '16%', width: '16.5%', height: '18%' },
|
|
1068
|
+
{ left: '77.5%', top: '16%', width: '16.5%', height: '18%' },
|
|
1069
|
+
{ left: '59%', top: '38%', width: '16.5%', height: '18%' },
|
|
1070
|
+
{ left: '77.5%', top: '38%', width: '16.5%', height: '18%' },
|
|
1071
|
+
{ left: '6%', top: '63%', width: '48%', height: '24%' },
|
|
1072
|
+
{ left: '59%', top: '61%', width: '35%', height: '17%' },
|
|
1073
|
+
{ left: '59%', top: '82%', width: '35%', height: '14%' },
|
|
1074
|
+
{ left: '59%', top: '16%', width: '35%', height: '40%' },
|
|
1075
|
+
];
|
|
1076
|
+
const healthRadarRegions = [
|
|
1077
|
+
{ left: '6%', top: '16%', width: '42%', height: '68%' },
|
|
1078
|
+
{ left: '52%', top: '16%', width: '42%', height: '32%' },
|
|
1079
|
+
{ left: '52%', top: '52%', width: '42%', height: '32%' },
|
|
1080
|
+
];
|
|
1081
|
+
const deviationRegions = [
|
|
1082
|
+
{ left: '6%', top: '16%', width: '48%', height: '58%' },
|
|
1083
|
+
{ left: '58%', top: '16%', width: '36%', height: '58%' },
|
|
1084
|
+
];
|
|
1085
|
+
const financeRiskRegions = [
|
|
1086
|
+
{ left: '6%', top: '16%', width: '56%', height: '46%' },
|
|
1087
|
+
{ left: '6%', top: '66%', width: '27%', height: '20%' },
|
|
1088
|
+
{ left: '36%', top: '66%', width: '27%', height: '20%' },
|
|
1089
|
+
{ left: '66%', top: '16%', width: '28%', height: '70%' },
|
|
1090
|
+
];
|
|
1091
|
+
const expenseRiskRegions = [
|
|
1092
|
+
{ left: '6%', top: '16%', width: '56%', height: '64%' },
|
|
1093
|
+
{ left: '66%', top: '16%', width: '28%', height: '64%' },
|
|
1094
|
+
];
|
|
1095
|
+
const deviationInsightRegions = [
|
|
1096
|
+
{ left: '6%', top: '18%', width: '88%', height: '18%' },
|
|
1097
|
+
{ left: '6%', top: '40%', width: '88%', height: '18%' },
|
|
1098
|
+
{ left: '6%', top: '62%', width: '88%', height: '18%' },
|
|
1099
|
+
];
|
|
1100
|
+
const organizationRiskRegions = [
|
|
1101
|
+
{ left: '6%', top: '18%', width: '28%', height: '56%' },
|
|
1102
|
+
{ left: '38%', top: '18%', width: '56%', height: '56%' },
|
|
1103
|
+
{ left: '6%', top: '78%', width: '28%', height: '14%' },
|
|
1104
|
+
{ left: '38%', top: '78%', width: '28%', height: '14%' },
|
|
1105
|
+
];
|
|
1106
|
+
const investmentRiskRegions = [
|
|
1107
|
+
{ left: '6%', top: '16%', width: '56%', height: '64%' },
|
|
1108
|
+
{ left: '66%', top: '16%', width: '28%', height: '64%' },
|
|
1109
|
+
];
|
|
1110
|
+
const executiveTodoRegions = [
|
|
1111
|
+
{ left: '6%', top: '16%', width: '88%', height: '20%' },
|
|
1112
|
+
{ left: '6%', top: '40%', width: '88%', height: '20%' },
|
|
1113
|
+
{ left: '6%', top: '64%', width: '88%', height: '20%' },
|
|
1114
|
+
];
|
|
1115
|
+
const shortcutDrillRegions = [
|
|
1116
|
+
{ left: '6%', top: '18%', width: '26%', height: '24%' },
|
|
1117
|
+
{ left: '37%', top: '18%', width: '26%', height: '24%' },
|
|
1118
|
+
{ left: '68%', top: '18%', width: '26%', height: '24%' },
|
|
1119
|
+
{ left: '6%', top: '50%', width: '26%', height: '24%' },
|
|
1120
|
+
{ left: '37%', top: '50%', width: '26%', height: '24%' },
|
|
1121
|
+
{ left: '68%', top: '50%', width: '26%', height: '24%' },
|
|
1122
|
+
];
|
|
1123
|
+
const quickWorkbenchRegions = [
|
|
1124
|
+
{ left: '6%', top: '14%', width: '88%', height: '20%' },
|
|
1125
|
+
{ left: '6%', top: '38%', width: '88%', height: '20%' },
|
|
1126
|
+
{ left: '6%', top: '62%', width: '88%', height: '20%' },
|
|
1127
|
+
{ left: '6%', top: '82%', width: '88%', height: '12%' },
|
|
1128
|
+
];
|
|
1129
|
+
const strategyKpiRegions = [
|
|
1130
|
+
{ left: '3%', top: '14%', width: '26%', height: '50%' },
|
|
1131
|
+
{ left: '32%', top: '14%', width: '20%', height: '24%' },
|
|
1132
|
+
{ left: '54%', top: '14%', width: '20%', height: '24%' },
|
|
1133
|
+
{ left: '76%', top: '14%', width: '20%', height: '24%' },
|
|
1134
|
+
{ left: '32%', top: '42%', width: '20%', height: '22%' },
|
|
1135
|
+
{ left: '54%', top: '42%', width: '20%', height: '22%' },
|
|
1136
|
+
{ left: '76%', top: '42%', width: '20%', height: '22%' },
|
|
1137
|
+
{ left: '3%', top: '70%', width: '93%', height: '18%' },
|
|
1138
|
+
];
|
|
1139
|
+
const operationHealthRegions = [
|
|
1140
|
+
{ left: '4%', top: '16%', width: '20%', height: '68%' },
|
|
1141
|
+
{ left: '26.5%', top: '16%', width: '38%', height: '68%' },
|
|
1142
|
+
{ left: '67%', top: '16%', width: '29%', height: '68%' },
|
|
1143
|
+
];
|
|
1144
|
+
const operationEfficiencyRegions = [
|
|
1145
|
+
{ left: '4%', top: '16%', width: '29%', height: '68%' },
|
|
1146
|
+
{ left: '35.5%', top: '16%', width: '29%', height: '68%' },
|
|
1147
|
+
{ left: '67%', top: '16%', width: '29%', height: '68%' },
|
|
1148
|
+
];
|
|
1149
|
+
const businessMetricMatrixRegions = [
|
|
1150
|
+
{ left: '4%', top: '16%', width: '27%', height: '24%' },
|
|
1151
|
+
{ left: '33%', top: '16%', width: '27%', height: '24%' },
|
|
1152
|
+
{ left: '62%', top: '16%', width: '34%', height: '24%' },
|
|
1153
|
+
{ left: '4%', top: '46%', width: '46%', height: '38%' },
|
|
1154
|
+
{ left: '53%', top: '46%', width: '43%', height: '38%' },
|
|
1155
|
+
{ left: '4%', top: '86%', width: '92%', height: '10%' },
|
|
1156
|
+
];
|
|
1157
|
+
const hrOrganizationRegions = [
|
|
1158
|
+
{ left: '5%', top: '18%', width: '24%', height: '28%' },
|
|
1159
|
+
{ left: '5%', top: '52%', width: '40%', height: '34%' },
|
|
1160
|
+
{ left: '50%', top: '18%', width: '45%', height: '68%' },
|
|
1161
|
+
];
|
|
1162
|
+
const hrRiskComplianceRegions = [
|
|
1163
|
+
{ left: '5%', top: '18%', width: '28%', height: '30%' },
|
|
1164
|
+
{ left: '36%', top: '18%', width: '28%', height: '30%' },
|
|
1165
|
+
{ left: '67%', top: '18%', width: '28%', height: '30%' },
|
|
1166
|
+
{ left: '5%', top: '54%', width: '90%', height: '32%' },
|
|
1167
|
+
];
|
|
1168
|
+
const hrPeopleCostRegions = [
|
|
1169
|
+
{ left: '5%', top: '18%', width: '38%', height: '64%' },
|
|
1170
|
+
{ left: '48%', top: '18%', width: '47%', height: '64%' },
|
|
1171
|
+
{ left: '5%', top: '84%', width: '90%', height: '10%' },
|
|
1172
|
+
];
|
|
1173
|
+
const hrTalentTodoRegions = [
|
|
1174
|
+
{ left: '5%', top: '18%', width: '25%', height: '68%' },
|
|
1175
|
+
{ left: '35%', top: '18%', width: '34%', height: '32%' },
|
|
1176
|
+
{ left: '35%', top: '54%', width: '34%', height: '32%' },
|
|
1177
|
+
{ left: '74%', top: '18%', width: '21%', height: '68%' },
|
|
1178
|
+
];
|
|
1179
|
+
const fallbackColumn = index % 2;
|
|
1180
|
+
const fallbackRow = Math.floor(index / 2);
|
|
1181
|
+
const fallbackRegion: ReferenceCompositeRegion = {
|
|
1182
|
+
left: `${6 + fallbackColumn * 46}%`,
|
|
1183
|
+
top: `${14 + (fallbackRow % 2) * 34}%`,
|
|
1184
|
+
width: '40%',
|
|
1185
|
+
height: '28%',
|
|
1186
|
+
};
|
|
1187
|
+
const semanticIndex = referenceCompositeDiagnosticIndex(kind, nestedBlock, index);
|
|
1188
|
+
const region = referenceCompositeDiagnosticRegionByLayout(nestedBlock, nestedBlocks) ?? (kind === 'ops'
|
|
1189
|
+
? opsRegions[semanticIndex]
|
|
1190
|
+
: kind === 'security'
|
|
1191
|
+
? securityRegions[semanticIndex]
|
|
1192
|
+
: kind === 'asset'
|
|
1193
|
+
? assetRegions[semanticIndex]
|
|
1194
|
+
: kind === 'project'
|
|
1195
|
+
? projectRegions[semanticIndex]
|
|
1196
|
+
: kind === 'riskSummary'
|
|
1197
|
+
? riskSummaryRegions[semanticIndex]
|
|
1198
|
+
: kind === 'healthRadar'
|
|
1199
|
+
? healthRadarRegions[semanticIndex]
|
|
1200
|
+
: kind === 'deviation'
|
|
1201
|
+
? deviationRegions[semanticIndex]
|
|
1202
|
+
: kind === 'financeRisk'
|
|
1203
|
+
? financeRiskRegions[semanticIndex]
|
|
1204
|
+
: kind === 'expenseRisk'
|
|
1205
|
+
? expenseRiskRegions[semanticIndex]
|
|
1206
|
+
: kind === 'deviationInsight'
|
|
1207
|
+
? deviationInsightRegions[semanticIndex]
|
|
1208
|
+
: kind === 'organizationRisk'
|
|
1209
|
+
? organizationRiskRegions[semanticIndex]
|
|
1210
|
+
: kind === 'investmentRisk'
|
|
1211
|
+
? investmentRiskRegions[semanticIndex]
|
|
1212
|
+
: kind === 'executiveTodo'
|
|
1213
|
+
? executiveTodoRegions[semanticIndex]
|
|
1214
|
+
: kind === 'shortcutDrill'
|
|
1215
|
+
? shortcutDrillRegions[semanticIndex]
|
|
1216
|
+
: kind === 'quickWorkbench'
|
|
1217
|
+
? quickWorkbenchRegions[semanticIndex]
|
|
1218
|
+
: kind === 'strategyKpi'
|
|
1219
|
+
? strategyKpiRegions[semanticIndex]
|
|
1220
|
+
: kind === 'operationHealth'
|
|
1221
|
+
? operationHealthRegions[semanticIndex]
|
|
1222
|
+
: kind === 'operationEfficiency'
|
|
1223
|
+
? operationEfficiencyRegions[semanticIndex]
|
|
1224
|
+
: kind === 'businessMetricMatrix'
|
|
1225
|
+
? businessMetricMatrixRegions[semanticIndex]
|
|
1226
|
+
: kind === 'hrOrganization'
|
|
1227
|
+
? hrOrganizationRegions[semanticIndex]
|
|
1228
|
+
: kind === 'hrRiskCompliance'
|
|
1229
|
+
? hrRiskComplianceRegions[semanticIndex]
|
|
1230
|
+
: kind === 'hrPeopleCost'
|
|
1231
|
+
? hrPeopleCostRegions[semanticIndex]
|
|
1232
|
+
: kind === 'hrTalentTodo'
|
|
1233
|
+
? hrTalentTodoRegions[semanticIndex]
|
|
1234
|
+
: undefined) ?? fallbackRegion;
|
|
1235
|
+
return {
|
|
1236
|
+
position: 'absolute',
|
|
1237
|
+
...region,
|
|
1238
|
+
minWidth: '28px',
|
|
1239
|
+
minHeight: '28px',
|
|
1240
|
+
zIndex: -1,
|
|
1241
|
+
opacity: 0,
|
|
1242
|
+
pointerEvents: 'none',
|
|
1243
|
+
overflow: 'hidden',
|
|
1244
|
+
color: 'transparent',
|
|
1245
|
+
backgroundColor: 'transparent',
|
|
1246
|
+
borderColor: 'transparent',
|
|
1247
|
+
};
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
/**
|
|
1251
|
+
* Builds a diagnostic marker from screenshot nested layout coordinates when available.
|
|
1252
|
+
* @param nestedBlock - Nested child card represented by the diagnostic marker.
|
|
1253
|
+
* @returns Percentage box in the parent composite, or undefined when no safe layout exists.
|
|
1254
|
+
*/
|
|
1255
|
+
function referenceCompositeDiagnosticRegionByLayout(nestedBlock: CustomCanvasNestedBlock, nestedBlocks: readonly CustomCanvasNestedBlock[]): ReferenceCompositeRegion | undefined {
|
|
1256
|
+
const layout = isRecord(nestedBlock.layout as unknown) ? nestedBlock.layout as unknown as Record<string, unknown> : {};
|
|
1257
|
+
const x = numberValue(layout.x, Number.NaN);
|
|
1258
|
+
const y = numberValue(layout.y, Number.NaN);
|
|
1259
|
+
const w = numberValue(layout.w, Number.NaN);
|
|
1260
|
+
const h = numberValue(layout.h, Number.NaN);
|
|
1261
|
+
if (![x, y, w, h].every(Number.isFinite) || w <= 0 || h <= 0) return undefined;
|
|
1262
|
+
const data = isRecord(nestedBlock.data) ? nestedBlock.data as Record<string, unknown> : {};
|
|
1263
|
+
const parentSource = layout.parentId || data.parentBlockId || '';
|
|
1264
|
+
if (!parentSource) return undefined;
|
|
1265
|
+
const parentId = String(parentSource);
|
|
1266
|
+
const basis = referenceCompositeLayoutBasis(referenceCompositeSiblingLayouts(nestedBlocks, parentId));
|
|
1267
|
+
if (!basis) return undefined;
|
|
1268
|
+
const left = ((x - basis.minX) / basis.width) * 100;
|
|
1269
|
+
const top = ((y - basis.minY) / basis.height) * 100;
|
|
1270
|
+
const width = (w / basis.width) * 100;
|
|
1271
|
+
const height = (h / basis.height) * 100;
|
|
1272
|
+
if ([left, top, width, height].some((value) => !Number.isFinite(value))) return undefined;
|
|
1273
|
+
return {
|
|
1274
|
+
left: `${clampPercent(left)}%`,
|
|
1275
|
+
top: `${clampPercent(top)}%`,
|
|
1276
|
+
width: `${clampPercent(width, 3, 100)}%`,
|
|
1277
|
+
height: `${clampPercent(height, 3, 100)}%`,
|
|
1278
|
+
};
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
/**
|
|
1282
|
+
* Reads sibling layout boxes from the parent-local nested layout payload when present.
|
|
1283
|
+
* @param nestedBlock - Current nested child card.
|
|
1284
|
+
* @returns Safe sibling layout boxes from the same parent.
|
|
1285
|
+
*/
|
|
1286
|
+
function referenceCompositeSiblingLayouts(nestedBlocks: readonly CustomCanvasNestedBlock[], parentId: string): Array<{ x: number; y: number; w: number; h: number }> {
|
|
1287
|
+
return nestedBlocks.flatMap((item) => {
|
|
1288
|
+
const layout = isRecord(item.layout as unknown) ? item.layout as unknown as Record<string, unknown> : {};
|
|
1289
|
+
const data = isRecord(item.data) ? item.data as Record<string, unknown> : {};
|
|
1290
|
+
const itemParentId = String(layout.parentId || data.parentBlockId || '');
|
|
1291
|
+
if (itemParentId !== parentId) return [];
|
|
1292
|
+
const x = numberValue(layout.x, Number.NaN);
|
|
1293
|
+
const y = numberValue(layout.y, Number.NaN);
|
|
1294
|
+
const w = numberValue(layout.w, Number.NaN);
|
|
1295
|
+
const h = numberValue(layout.h, Number.NaN);
|
|
1296
|
+
return [x, y, w, h].every(Number.isFinite) && w > 0 && h > 0 ? [{ x, y, w, h }] : [];
|
|
1297
|
+
});
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
/**
|
|
1301
|
+
* Calculates the smallest source-layout frame that contains nested diagnostic boxes.
|
|
1302
|
+
* @param boxes - Nested child layout boxes.
|
|
1303
|
+
* @returns Source-layout basis for percentage conversion.
|
|
1304
|
+
*/
|
|
1305
|
+
function referenceCompositeLayoutBasis(boxes: Array<{ x: number; y: number; w: number; h: number }>): { minX: number; minY: number; width: number; height: number } | undefined {
|
|
1306
|
+
if (boxes.length === 0) return undefined;
|
|
1307
|
+
const minX = Math.min(...boxes.map((box) => box.x));
|
|
1308
|
+
const minY = Math.min(...boxes.map((box) => box.y));
|
|
1309
|
+
const maxX = Math.max(...boxes.map((box) => box.x + box.w));
|
|
1310
|
+
const maxY = Math.max(...boxes.map((box) => box.y + box.h));
|
|
1311
|
+
const width = maxX - minX;
|
|
1312
|
+
const height = maxY - minY;
|
|
1313
|
+
return width > 0 && height > 0 ? { minX, minY, width, height } : undefined;
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
/**
|
|
1317
|
+
* Clamps a percentage value into a safe CSS range.
|
|
1318
|
+
* @param value - Raw percentage value.
|
|
1319
|
+
* @param min - Minimum percentage.
|
|
1320
|
+
* @param max - Maximum percentage.
|
|
1321
|
+
* @returns Rounded and clamped percentage.
|
|
1322
|
+
*/
|
|
1323
|
+
function clampPercent(value: number, min = 0, max = 100): number {
|
|
1324
|
+
return Math.round(Math.min(max, Math.max(min, value)) * 1000) / 1000;
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
/**
|
|
1328
|
+
* Maps a nested child card to the reference composite region it visually represents.
|
|
1329
|
+
* @param kind - Reference composite family currently rendered.
|
|
1330
|
+
* @param nestedBlock - Nested child card represented by the diagnostic marker.
|
|
1331
|
+
* @param fallbackIndex - Original child order used when no semantic slot matches.
|
|
1332
|
+
* @returns Region index inside the composite family geometry table.
|
|
1333
|
+
*/
|
|
1334
|
+
function referenceCompositeDiagnosticIndex(kind: ReferenceCompositeKind, nestedBlock: CustomCanvasNestedBlock, fallbackIndex: number): number {
|
|
1335
|
+
const text = nestedBlockClassifierText(nestedBlock);
|
|
1336
|
+
const visualKind = nestedBlockVisualKind(nestedBlock);
|
|
1337
|
+
if (kind === 'riskSummary') {
|
|
1338
|
+
if (/经营健康|综合得分|health|score/i.test(text)) return 0;
|
|
1339
|
+
if (/重大经营风险|major/i.test(text)) return 1;
|
|
1340
|
+
if (/预算严重偏差|budget/i.test(text)) return 2;
|
|
1341
|
+
if (/资金类预警|capital|fund/i.test(text)) return 3;
|
|
1342
|
+
if (/项目隐患|project/i.test(text)) return 4;
|
|
1343
|
+
if (/TODAY MOVEMENT|今日|movement/i.test(text)) return 5;
|
|
1344
|
+
}
|
|
1345
|
+
if (kind === 'businessMetricMatrix') {
|
|
1346
|
+
if (visualKind === 'chart' || visualKind === 'resourceBars' || visualKind === 'donut') return 3 + (fallbackIndex % 2);
|
|
1347
|
+
if (visualKind === 'list' || visualKind === 'simpleList' || visualKind === 'incidentList' || visualKind === 'quickLinks') return 4 + (fallbackIndex % 2);
|
|
1348
|
+
return Math.min(fallbackIndex, 2);
|
|
1349
|
+
}
|
|
1350
|
+
if (kind === 'hrOrganization') {
|
|
1351
|
+
if (/平均司龄|司龄|编制使用/i.test(text)) return 0;
|
|
1352
|
+
if (/部门编制|编制达成|人员结构/i.test(text)) return 1;
|
|
1353
|
+
if (visualKind === 'chart' || /关键异动|趋势|流动/i.test(text)) return 2;
|
|
1354
|
+
return Math.min(fallbackIndex, 2);
|
|
1355
|
+
}
|
|
1356
|
+
if (kind === 'hrRiskCompliance') {
|
|
1357
|
+
if (/迟到/i.test(text)) return 0;
|
|
1358
|
+
if (/旷工|缺勤/i.test(text)) return 1;
|
|
1359
|
+
if (/请假|超标/i.test(text)) return 2;
|
|
1360
|
+
return 3;
|
|
1361
|
+
}
|
|
1362
|
+
if (kind === 'hrPeopleCost') {
|
|
1363
|
+
if (/薪酬结构|结构|总成本/i.test(text)) return 0;
|
|
1364
|
+
if (visualKind === 'chart' || /成本趋势|趋势|薪酬成本/i.test(text)) return 1;
|
|
1365
|
+
return 2;
|
|
1366
|
+
}
|
|
1367
|
+
if (kind === 'hrTalentTodo') {
|
|
1368
|
+
if (/储备|继任|培训|梯队/i.test(text)) return fallbackIndex % 3;
|
|
1369
|
+
if (/待办|人事|审批|入职|转正/i.test(text)) return 3;
|
|
1370
|
+
if (/人效|排行|排名/i.test(text)) return 3;
|
|
1371
|
+
return Math.min(fallbackIndex, 3);
|
|
1372
|
+
}
|
|
1373
|
+
if (kind === 'project') {
|
|
1374
|
+
const projectIndex = referenceProjectDiagnosticIndex(text, visualKind);
|
|
1375
|
+
if (projectIndex !== undefined) return projectIndex;
|
|
1376
|
+
}
|
|
1377
|
+
if (kind === 'ops') {
|
|
1378
|
+
if (visualKind === 'statusList' || /服务监控|鏈嶅姟鐩戞帶|service/i.test(text)) return 0;
|
|
1379
|
+
if (visualKind === 'incidentList' || /故障|告警|鏁呴殰|鍛婅|incident|alarm/i.test(text)) return 1;
|
|
1380
|
+
if (visualKind === 'resourceBars' || /资源|负载|CPU|内存|存储|带宽|璧勬簮|璐熻浇/i.test(text)) return 2;
|
|
1381
|
+
if (visualKind === 'chart' || /趋势|近七日|瓒嬪娍|杩戜竷鏃?/i.test(text)) return 3;
|
|
1382
|
+
}
|
|
1383
|
+
if (kind === 'security') {
|
|
1384
|
+
if (visualKind === 'securityScore' || /安全风险|安全健康|瀹夊叏椋庨櫓|瀹夊叏鍋ュ悍|security/i.test(text)) return 0;
|
|
1385
|
+
if (/账号|权限|弱口令|离职|超权|璐﹀彿|鏉冮檺|寮卞彛|绂昏亴|瓒呮潈/i.test(text)) return 2;
|
|
1386
|
+
if (/合规|审计|等保|隐私|日志|鍚堣|瀹¤|绛変繚|闅愮|鏃ュ織/i.test(text)) return 2;
|
|
1387
|
+
return 1;
|
|
1388
|
+
}
|
|
1389
|
+
if (kind === 'asset' && /成本运营|成本优化|云费用|降本|预算执行/i.test(text)) return 3;
|
|
1390
|
+
if (kind === 'asset' && /资产运营|闲置|盘点/i.test(text)) return 2;
|
|
1391
|
+
if (kind === 'asset' && /成本分析|预算分析/i.test(text)) return 1;
|
|
1392
|
+
if (kind === 'asset') {
|
|
1393
|
+
if (visualKind === 'donut' || /成本分析|预算分析|鎴愭湰鍒嗘瀽|棰勭畻鍒嗘瀽|donut/i.test(text)) return 1;
|
|
1394
|
+
if (/成本优化|云费用|降本|预算执行|鎴愭湰浼樺寲|浜戣垂鐢?|闄嶆湰|棰勭畻鎵ц/i.test(text)) return 3;
|
|
1395
|
+
if (/资产运营|闲置|License|盘点|璧勪骇杩愯惀|闂茬疆|鐩樼偣/i.test(text)) return 2;
|
|
1396
|
+
if (visualKind === 'metric' || /资产台账|终端|服务器|机房|云主机|存储|璧勪骇鍙拌处|缁堢|鏈嶅姟鍣?|浜戜富鏈?/i.test(text)) return 0;
|
|
1397
|
+
}
|
|
1398
|
+
if (kind === 'healthRadar') {
|
|
1399
|
+
if (visualKind === 'chart' || /雷达|五大维度|健康/i.test(text)) return 0;
|
|
1400
|
+
if (/盈利结构|利润|低毛利|亏损/i.test(text)) return 1;
|
|
1401
|
+
if (/资金安全|逾期应收|资金/i.test(text)) return 2;
|
|
1402
|
+
}
|
|
1403
|
+
if (kind === 'deviation') {
|
|
1404
|
+
if (visualKind === 'chart' || /目标完成|目标\s*VS|柱线|偏差/i.test(text)) return 0;
|
|
1405
|
+
if (/利润底线|底线失守|亏损源/i.test(text)) return 1;
|
|
1406
|
+
}
|
|
1407
|
+
if (kind === 'financeRisk') {
|
|
1408
|
+
if (visualKind === 'chart' || /资金风险趋势|趋势|红线/i.test(text)) return 0;
|
|
1409
|
+
if (/逾期应收|风险敞口/i.test(text)) return 1;
|
|
1410
|
+
if (/现金流|经营现金/i.test(text)) return 2;
|
|
1411
|
+
if (/坏账|预警|隐患/i.test(text)) return 3;
|
|
1412
|
+
}
|
|
1413
|
+
if (kind === 'expenseRisk') {
|
|
1414
|
+
if (visualKind === 'chart' || /费用超支|排行|管理费用|外包成本/i.test(text)) return 0;
|
|
1415
|
+
if (/超阈值|冻结|审计/i.test(text)) return 1;
|
|
1416
|
+
}
|
|
1417
|
+
if (kind === 'deviationInsight') {
|
|
1418
|
+
if (/利润同比|利润|下滑|事业部/i.test(text)) return 0;
|
|
1419
|
+
if (/费用环比|管理费用|异动/i.test(text)) return 1;
|
|
1420
|
+
if (/预算偏离|新基地|预算/i.test(text)) return 2;
|
|
1421
|
+
}
|
|
1422
|
+
if (kind === 'organizationRisk') {
|
|
1423
|
+
if (/组织稳定|稳定分/i.test(text)) return 0;
|
|
1424
|
+
if (visualKind === 'chart' || /人效风险|趋势/i.test(text)) return 1;
|
|
1425
|
+
if (/核心流失|流失率/i.test(text)) return 2;
|
|
1426
|
+
if (/人效下滑|超编/i.test(text)) return 3;
|
|
1427
|
+
}
|
|
1428
|
+
if (kind === 'investmentRisk') {
|
|
1429
|
+
if (visualKind === 'chart' || /项目风险排行|甘特|新基地|技改|合资/i.test(text)) return 0;
|
|
1430
|
+
if (/战略项目|落地滞后|延期|超支/i.test(text)) return 1;
|
|
1431
|
+
}
|
|
1432
|
+
if (kind === 'executiveTodo') {
|
|
1433
|
+
if (/战略投资|追加预算/i.test(text)) return 0;
|
|
1434
|
+
if (/资金支付|复核|大额资金/i.test(text)) return 1;
|
|
1435
|
+
if (/人事|任免|组织部|超期/i.test(text)) return 2;
|
|
1436
|
+
}
|
|
1437
|
+
if (kind === 'shortcutDrill') {
|
|
1438
|
+
if (/亏损主体|利润/i.test(text)) return 0;
|
|
1439
|
+
if (/资金风险|资金/i.test(text)) return 1;
|
|
1440
|
+
if (/违规|合规|担保/i.test(text)) return 2;
|
|
1441
|
+
if (/延期|项目/i.test(text)) return 3;
|
|
1442
|
+
if (/费用超支|费用/i.test(text)) return 4;
|
|
1443
|
+
if (/组织隐患|组织/i.test(text)) return 5;
|
|
1444
|
+
}
|
|
1445
|
+
if (kind === 'quickWorkbench') {
|
|
1446
|
+
if (/待办|审批|加急|urgent|todo/i.test(text)) return 0;
|
|
1447
|
+
if (/报表|月报|分析|report/i.test(text)) return 1;
|
|
1448
|
+
if (/系统|入口|财务|供应链|HR|BI|platform|quick/i.test(text)) return 2;
|
|
1449
|
+
if (/消息|提醒|预警|通知|message|notice/i.test(text)) return 3;
|
|
1450
|
+
}
|
|
1451
|
+
if (kind === 'strategyKpi') {
|
|
1452
|
+
if (/营收|收入|营业收入|revenue/i.test(text)) return 0;
|
|
1453
|
+
if (/利润|净利率|profit/i.test(text)) return 1;
|
|
1454
|
+
if (/现金流|cash/i.test(text)) return 2;
|
|
1455
|
+
if (/用户|订单|客户|customer|order/i.test(text)) return 3;
|
|
1456
|
+
if (/完成率|目标|target/i.test(text)) return 4;
|
|
1457
|
+
if (/项目|project/i.test(text)) return 5;
|
|
1458
|
+
if (/份额|share/i.test(text)) return 6;
|
|
1459
|
+
if (/预警|风险|warning|risk/i.test(text)) return 7;
|
|
1460
|
+
}
|
|
1461
|
+
if (kind === 'operationHealth') {
|
|
1462
|
+
if (/目标进度|进度条|目标|完成/i.test(text)) return 0;
|
|
1463
|
+
if (visualKind === 'chart' && /结构|占比|饼|donut|pie/i.test(text)) return 2;
|
|
1464
|
+
if (/结构占比|收入结构|业务结构|渠道结构|区域结构/i.test(text)) return 2;
|
|
1465
|
+
if (/近\s*6\s*个月|核心指标|趋势|同比|预算线|业务线|区域|line|trend/i.test(text)) return 1;
|
|
1466
|
+
return Math.min(fallbackIndex, 2);
|
|
1467
|
+
}
|
|
1468
|
+
if (kind === 'operationEfficiency') {
|
|
1469
|
+
if (/交付|履约|订单准时|生产良率/i.test(text)) return 0;
|
|
1470
|
+
if (/资源利用|人均产值|服务响应|设备利用|库存周转/i.test(text)) return 1;
|
|
1471
|
+
if (/重点项目里程碑|里程碑|数字化工厂|成本专项|渠道升级|新品上市/i.test(text)) return 2;
|
|
1472
|
+
return Math.min(fallbackIndex, 2);
|
|
1473
|
+
}
|
|
1474
|
+
if (kind === 'project') {
|
|
1475
|
+
if (visualKind === 'progressList' || /项目看板|项目进度|重点 IT|椤圭洰鐪嬫澘|椤圭洰杩涘害/i.test(text)) return 0;
|
|
1476
|
+
if (visualKind === 'todoGrid' || /待办|审批|寰呭姙|瀹℃壒/i.test(text)) return 1;
|
|
1477
|
+
if (/研发|运维效能|BUG|上线|鐮斿彂|杩愮淮鏁堣兘/i.test(text)) return 2;
|
|
1478
|
+
if (/割接|巡检|排期|今晚|周[一二三四五六日]|需审批|已排期/i.test(text)) return 3;
|
|
1479
|
+
if (visualKind === 'quickLinks' || /快捷|入口|通知|平台|蹇嵎|鍏ュ彛|閫氱煡|骞冲彴/i.test(text)) return 3;
|
|
1480
|
+
}
|
|
1481
|
+
return fallbackIndex;
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
/**
|
|
1485
|
+
* Maps project-panel nested cards to fine-grained diagnostic boxes matching the visible template.
|
|
1486
|
+
* @param text - Classifier text from title, renderer metadata, and item labels.
|
|
1487
|
+
* @param visualKind - Visual kind inferred for the nested card.
|
|
1488
|
+
* @returns Region index in the project reference diagnostic grid, or undefined for legacy fallback.
|
|
1489
|
+
*/
|
|
1490
|
+
function referenceProjectDiagnosticIndex(text: string, visualKind: NestedBlockVisualKind): number | undefined {
|
|
1491
|
+
if (visualKind === 'progressList' || /重点\s*IT|项目看板|项目进度|数据中台|供应链|统一身份|容灾|椤圭洰鐪嬫澘|椤圭洰杩涘害|閲嶇偣 IT/.test(text)) return 0;
|
|
1492
|
+
if (/IT\s*采购|采购审批|閲囪喘瀹℃壒/.test(text)) return 1;
|
|
1493
|
+
if (/系统上线|上线审批|涓婄嚎瀹℃壒/.test(text)) return 2;
|
|
1494
|
+
if (/权限变更|鏉冮檺鍙樻洿/.test(text)) return 3;
|
|
1495
|
+
if (/安全整改|瀹夊叏鏁存敼/.test(text)) return 4;
|
|
1496
|
+
if (/研发|效能|上线频次|交付周期|BUG|鐮斬彂|鐮斿彂|杩愮淮鏁堣兘/.test(text)) return 5;
|
|
1497
|
+
if (visualKind === 'quickLinks' || /快捷|入口|运维平台|堡垒机|服务工单|蹇嵎|鍏ュ彛|骞冲彴/.test(text)) return 6;
|
|
1498
|
+
if (/订单中台|灰度割接|机房巡检|备份巡检|今晚|周五|需审批|已排期|鍓叉帴|宸℃|浠婃櫄|闇€瀹℃壒|宸叉帓/.test(text)) return 7;
|
|
1499
|
+
if (visualKind === 'todoGrid' || /待办|审批|寰呭姙|瀹℃壒/.test(text)) return 8;
|
|
1500
|
+
return undefined;
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
/**
|
|
1504
|
+
* Finds a nested child card by title pattern.
|
|
1505
|
+
* @param data - Custom canvas renderer data.
|
|
1506
|
+
* @param pattern - Pattern matched against nested child titles.
|
|
1507
|
+
* @returns First matching nested child card.
|
|
1508
|
+
*/
|
|
1509
|
+
function referenceNestedBlock(data: CustomCanvasData, pattern: RegExp): CustomCanvasNestedBlock | undefined {
|
|
1510
|
+
const nestedBlocks = Array.isArray(data.nestedBlocks) ? data.nestedBlocks : [];
|
|
1511
|
+
return nestedBlocks.find((nestedBlock) => pattern.test(nestedBlock.title));
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
/**
|
|
1515
|
+
* Builds a compact metric/list item from a nested child card.
|
|
1516
|
+
* @param data - Custom canvas renderer data.
|
|
1517
|
+
* @param label - Display label used when the child exists.
|
|
1518
|
+
* @param pattern - Pattern matched against nested child titles.
|
|
1519
|
+
* @param fallbackValue - Value used when the child is absent.
|
|
1520
|
+
* @param tone - Visual tone for the item.
|
|
1521
|
+
* @returns Normalized reference-preview item.
|
|
1522
|
+
*/
|
|
1523
|
+
function referenceMetricItem(
|
|
1524
|
+
data: CustomCanvasData,
|
|
1525
|
+
label: string,
|
|
1526
|
+
pattern: RegExp,
|
|
1527
|
+
fallbackValue: string,
|
|
1528
|
+
tone: 'healthy' | 'warning' | 'critical' | 'info' | 'violet' | 'neutral' = 'neutral',
|
|
1529
|
+
): Record<string, unknown> {
|
|
1530
|
+
const item = referenceNestedMetricItem(data, pattern);
|
|
1531
|
+
const block = item ? undefined : referenceNestedBlock(data, pattern);
|
|
1532
|
+
return {
|
|
1533
|
+
label,
|
|
1534
|
+
value: item ? nestedBlockItemValue(item) : block ? nestedBlockMetricValue(block) : fallbackValue,
|
|
1535
|
+
tone,
|
|
1536
|
+
};
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
/**
|
|
1540
|
+
* Finds a metric row inside nested cards when recognition grouped several screenshot metrics together.
|
|
1541
|
+
* @param data - Custom canvas renderer data.
|
|
1542
|
+
* @param pattern - Pattern matched against metric labels and row text.
|
|
1543
|
+
* @returns Matching item row when present.
|
|
1544
|
+
*/
|
|
1545
|
+
function referenceNestedMetricItem(data: CustomCanvasData, pattern: RegExp): Record<string, unknown> | undefined {
|
|
1546
|
+
const nestedBlocks = Array.isArray(data.nestedBlocks) ? data.nestedBlocks : [];
|
|
1547
|
+
for (const nestedBlock of nestedBlocks) {
|
|
1548
|
+
const item = nestedBlockRawItems(nestedBlock).find((candidate: Record<string, unknown>, index: number) => {
|
|
1549
|
+
const text = [
|
|
1550
|
+
nestedBlockItemLabel(candidate, index),
|
|
1551
|
+
nestedBlockItemValue(candidate),
|
|
1552
|
+
nestedBlockItemDetail(candidate),
|
|
1553
|
+
].filter(Boolean).join(' ');
|
|
1554
|
+
return pattern.test(text);
|
|
1555
|
+
});
|
|
1556
|
+
if (item) return item;
|
|
1557
|
+
}
|
|
1558
|
+
return undefined;
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
/**
|
|
1562
|
+
* Returns the main value for one KPI inside the risk summary band.
|
|
1563
|
+
* @param data - Custom canvas renderer data.
|
|
1564
|
+
* @param pattern - Nested card title pattern.
|
|
1565
|
+
* @param fallbackValue - Value used when OCR data is missing.
|
|
1566
|
+
* @returns Display value with screenshot units preserved when available.
|
|
1567
|
+
*/
|
|
1568
|
+
function referenceRiskMetricValue(data: CustomCanvasData, pattern: RegExp, fallbackValue: string): string {
|
|
1569
|
+
const item = referenceNestedMetricItem(data, pattern);
|
|
1570
|
+
if (item) return nestedBlockItemValue(item) || fallbackValue;
|
|
1571
|
+
const block = referenceNestedBlock(data, pattern);
|
|
1572
|
+
return block ? nestedBlockMetricValue(block) : fallbackValue;
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
/**
|
|
1576
|
+
* Normalizes risk KPI values to the large-number style used in the source band.
|
|
1577
|
+
* @param value - OCR or binding value, sometimes including the Chinese unit 项.
|
|
1578
|
+
* @returns Numeric display value without the unit suffix.
|
|
1579
|
+
*/
|
|
1580
|
+
function referenceRiskKpiValue(value: string): string {
|
|
1581
|
+
return value.replace(/\s*项$/u, '').trim() || value;
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
/**
|
|
1585
|
+
* Returns KPI tiles for the first-viewport risk summary band.
|
|
1586
|
+
* @param data - Custom canvas renderer data.
|
|
1587
|
+
* @returns Four KPI tile rows matching the screenshot order.
|
|
1588
|
+
*/
|
|
1589
|
+
function referenceRiskKpiItems(data: CustomCanvasData): Array<{ label: string; value: string; detail: string; tone: 'critical' | 'warning' }> {
|
|
1590
|
+
return [
|
|
1591
|
+
{
|
|
1592
|
+
label: '重大经营风险',
|
|
1593
|
+
value: referenceRiskKpiValue(referenceRiskMetricValue(data, /重大经营风险|major/i, '8')),
|
|
1594
|
+
detail: '亏损主体与毛利下滑集中',
|
|
1595
|
+
tone: 'critical',
|
|
1596
|
+
},
|
|
1597
|
+
{
|
|
1598
|
+
label: '预算严重偏差',
|
|
1599
|
+
value: referenceRiskKpiValue(referenceRiskMetricValue(data, /预算严重偏差|budget/i, '6')),
|
|
1600
|
+
detail: '费用超阈值连续两期',
|
|
1601
|
+
tone: 'warning',
|
|
1602
|
+
},
|
|
1603
|
+
{
|
|
1604
|
+
label: '资金类预警',
|
|
1605
|
+
value: referenceRiskKpiValue(referenceRiskMetricValue(data, /资金类预警|capital|fund/i, '14')),
|
|
1606
|
+
detail: '逾期应收触碰红线',
|
|
1607
|
+
tone: 'critical',
|
|
1608
|
+
},
|
|
1609
|
+
{
|
|
1610
|
+
label: '项目隐患',
|
|
1611
|
+
value: referenceRiskKpiValue(referenceRiskMetricValue(data, /项目隐患|project/i, '5')),
|
|
1612
|
+
detail: '延期叠加投资超支',
|
|
1613
|
+
tone: 'warning',
|
|
1614
|
+
},
|
|
1615
|
+
];
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
/**
|
|
1619
|
+
* Returns today movement rows for the risk summary band.
|
|
1620
|
+
* @param data - Custom canvas renderer data.
|
|
1621
|
+
* @returns Movement list rows from OCR data or screenshot fallback rows.
|
|
1622
|
+
*/
|
|
1623
|
+
function referenceRiskMovementItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
1624
|
+
const movement = referenceNestedBlock(data, /TODAY MOVEMENT|今日|movement/i);
|
|
1625
|
+
if (!movement) {
|
|
1626
|
+
return [
|
|
1627
|
+
{ label: '2 家子公司毛利率环比大幅下滑' },
|
|
1628
|
+
{ label: '3 项费用超阈值预警,管理费用连续偏高' },
|
|
1629
|
+
{ label: '重大担保事项进入董事会复核' },
|
|
1630
|
+
];
|
|
1631
|
+
}
|
|
1632
|
+
const elementRows = referenceRiskMovementElementItems(movement);
|
|
1633
|
+
if (elementRows.length > 0) return elementRows.slice(0, 3);
|
|
1634
|
+
const rows = nestedBlockItems(movement).filter((item: Record<string, unknown>, index: number) => {
|
|
1635
|
+
const label = nestedBlockItemLabel(item, index);
|
|
1636
|
+
return label && !/^TODAY MOVEMENT$/i.test(label);
|
|
1637
|
+
});
|
|
1638
|
+
return rows.length > 0 ? rows.slice(0, 3) : [
|
|
1639
|
+
{ label: '2 家子公司毛利率环比大幅下滑' },
|
|
1640
|
+
{ label: '3 项费用超阈值预警,管理费用连续偏高' },
|
|
1641
|
+
{ label: '重大担保事项进入董事会复核' },
|
|
1642
|
+
];
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
/**
|
|
1646
|
+
* Reads TODAY MOVEMENT rows from OCR/customCanvas text elements when the movement card is not a list.
|
|
1647
|
+
* @param movement - Nested movement preview block.
|
|
1648
|
+
* @returns Movement row labels from recognized text elements.
|
|
1649
|
+
*/
|
|
1650
|
+
function referenceRiskMovementElementItems(movement: CustomCanvasNestedBlock): Array<Record<string, unknown>> {
|
|
1651
|
+
const data = (isRecord(movement.data) ? movement.data : {}) as Record<string, unknown>;
|
|
1652
|
+
const elements = Array.isArray(data.elements) ? data.elements : [];
|
|
1653
|
+
return elements
|
|
1654
|
+
.map((element, index): Record<string, unknown> | undefined => {
|
|
1655
|
+
if (!isRecord(element)) return undefined;
|
|
1656
|
+
const label = textValue(element.label, textValue(element.text, textValue(element.value)));
|
|
1657
|
+
if (!label || /^TODAY MOVEMENT$/i.test(label)) return undefined;
|
|
1658
|
+
return { label, value: textValue(element.value), order: index };
|
|
1659
|
+
})
|
|
1660
|
+
.filter((item): item is Record<string, unknown> => Boolean(item));
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
/**
|
|
1664
|
+
* Returns service status rows for the reference-style operations panel.
|
|
1665
|
+
* @param data - Custom canvas renderer data.
|
|
1666
|
+
* @returns Status rows built from a nested child or screenshot fallback data.
|
|
1667
|
+
*/
|
|
1668
|
+
function referenceOpsServiceItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
1669
|
+
const block = referenceNestedBlock(data, /服务监控|系统监控|在线/);
|
|
1670
|
+
return block
|
|
1671
|
+
? referenceOpsItemsFromBlock(block, 'statusList').slice(0, 5)
|
|
1672
|
+
: nestedBlockFallbackItems({ id: 'reference-ops-service', title: '全局服务监控', kind: 'list', slot: 'body', dataBindingStatus: 'none' }, 'statusList');
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
/**
|
|
1676
|
+
* Returns resource load rows for the reference-style operations panel.
|
|
1677
|
+
* @param data - Custom canvas renderer data.
|
|
1678
|
+
* @returns Resource utilization rows.
|
|
1679
|
+
*/
|
|
1680
|
+
function referenceOpsResourceItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
1681
|
+
const block = referenceNestedBlock(data, /资源负载|负载监控|CPU|内存|存储|带宽/) ?? referenceNestedBlock(data, /服务监控|系统监控|在线/);
|
|
1682
|
+
return block
|
|
1683
|
+
? referenceOpsItemsFromBlock(block, 'resourceBars').slice(0, 4)
|
|
1684
|
+
: nestedBlockFallbackItems({ id: 'reference-ops-resource', title: '资源负载监控', kind: 'chart', slot: 'body', dataBindingStatus: 'none' }, 'resourceBars');
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
/**
|
|
1688
|
+
* Returns incident rows for the reference-style operations panel.
|
|
1689
|
+
* @param data - Custom canvas renderer data.
|
|
1690
|
+
* @returns Fault and alert rows.
|
|
1691
|
+
*/
|
|
1692
|
+
function referenceOpsIncidentItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
1693
|
+
const block = referenceNestedBlock(data, /故障|告警|事件|红警/);
|
|
1694
|
+
return block
|
|
1695
|
+
? referenceOpsItemsFromBlock(block, 'incidentList').slice(0, 3)
|
|
1696
|
+
: nestedBlockFallbackItems({ id: 'reference-ops-incidents', title: '故障 & 告警中心', kind: 'list', slot: 'body', dataBindingStatus: 'none' }, 'incidentList');
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
/**
|
|
1700
|
+
* Returns ops rows from model/OCR data only when they are strong enough for the target template.
|
|
1701
|
+
* @param block - Nested ops child card.
|
|
1702
|
+
* @param visualKind - Target ops visual region.
|
|
1703
|
+
* @returns Strong element/model rows, or reference fallback rows.
|
|
1704
|
+
*/
|
|
1705
|
+
function referenceOpsItemsFromBlock(block: CustomCanvasNestedBlock, visualKind: NestedBlockVisualKind): Array<Record<string, unknown>> {
|
|
1706
|
+
const elementItems = nestedBlockElementItems(block, visualKind);
|
|
1707
|
+
if (elementItems.length > 0 && !nestedBlockItemsLookTooWeakForVisualKind(elementItems, visualKind)) return elementItems;
|
|
1708
|
+
const rawItems = nestedBlockRawItems(block);
|
|
1709
|
+
if (rawItems.length > 0 && !nestedBlockItemsLookTooWeakForVisualKind(rawItems, visualKind)) return rawItems;
|
|
1710
|
+
return nestedBlockFallbackItems(block, visualKind);
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
/**
|
|
1714
|
+
* Returns seven-day trend bar rows for the reference-style operations panel.
|
|
1715
|
+
* @param data - Custom canvas renderer data.
|
|
1716
|
+
* @returns Bar rows shaped like the source CIO panel.
|
|
1717
|
+
*/
|
|
1718
|
+
function referenceOpsTrendItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
1719
|
+
const block = referenceNestedBlock(data, /趋势|近七日|七日/);
|
|
1720
|
+
const rawItems = block ? nestedBlockRawItems(block) : [];
|
|
1721
|
+
if (rawItems.length > 0 && !nestedBlockItemsLookTooWeak(rawItems)) return rawItems.slice(0, 7);
|
|
1722
|
+
return [
|
|
1723
|
+
{ label: '周一', value: '6', progress: 42, tone: 'neutral' },
|
|
1724
|
+
{ label: '周二', value: '8', progress: 53, tone: 'info' },
|
|
1725
|
+
{ label: '周三', value: '5', progress: 35, tone: 'healthy' },
|
|
1726
|
+
{ label: '周四', value: '11', progress: 70, tone: 'warning' },
|
|
1727
|
+
{ label: '周五', value: '7', progress: 50, tone: 'info' },
|
|
1728
|
+
{ label: '周六', value: '13', progress: 88, tone: 'critical' },
|
|
1729
|
+
{ label: '周日', value: '8', progress: 56, tone: 'warning' },
|
|
1730
|
+
];
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
/**
|
|
1734
|
+
* Reads status-like OCR elements as compact rows for reference panels.
|
|
1735
|
+
* @param block - Nested child card carrying screenshot-recognized elements.
|
|
1736
|
+
* @returns Rows with label, value/status, and tone.
|
|
1737
|
+
*/
|
|
1738
|
+
function referenceStatusElementItems(block: CustomCanvasNestedBlock): Array<Record<string, unknown>> {
|
|
1739
|
+
const data = (isRecord(block.data) ? block.data : {}) as Record<string, unknown>;
|
|
1740
|
+
const elements = Array.isArray(data.elements) ? data.elements : [];
|
|
1741
|
+
return elements
|
|
1742
|
+
.map((element): Record<string, unknown> | undefined => {
|
|
1743
|
+
if (!isRecord(element)) return undefined;
|
|
1744
|
+
const label = textValue(element.label, textValue(element.title, textValue(element.text)));
|
|
1745
|
+
if (!label) return undefined;
|
|
1746
|
+
const status = textValue(element.status);
|
|
1747
|
+
const value = textValue(element.value, status);
|
|
1748
|
+
return {
|
|
1749
|
+
label,
|
|
1750
|
+
value,
|
|
1751
|
+
status,
|
|
1752
|
+
tone: nestedBlockToneFromStatus(`${label} ${value} ${status}`),
|
|
1753
|
+
};
|
|
1754
|
+
})
|
|
1755
|
+
.filter((item): item is Record<string, unknown> => Boolean(item));
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
/**
|
|
1759
|
+
* Checks whether a security row belongs in the compliance audit column.
|
|
1760
|
+
* @param item - Candidate row.
|
|
1761
|
+
* @param index - Candidate index.
|
|
1762
|
+
* @returns True for compliance and audit rows.
|
|
1763
|
+
*/
|
|
1764
|
+
function referenceSecurityAuditRow(item: Record<string, unknown>, index: number): boolean {
|
|
1765
|
+
const text = nestedBlockItemTitle(item, index);
|
|
1766
|
+
return /等保|隐私|日志|合规/.test(text) && !/账号|账户|权限|离职|超权|弱口令|操作/.test(text);
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
/**
|
|
1770
|
+
* Checks whether a security row belongs in the account and operation audit column.
|
|
1771
|
+
* @param item - Candidate row.
|
|
1772
|
+
* @param index - Candidate index.
|
|
1773
|
+
* @returns True for account, permission, and operation rows.
|
|
1774
|
+
*/
|
|
1775
|
+
function referenceSecurityAccountRow(item: Record<string, unknown>, index: number): boolean {
|
|
1776
|
+
return /账号|账户|权限|离职|超权|弱口令|操作/.test(nestedBlockItemTitle(item, index));
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
/**
|
|
1780
|
+
* Returns the security score child for the reference-style security panel.
|
|
1781
|
+
* @param data - Custom canvas renderer data.
|
|
1782
|
+
* @returns Nested block that carries score/risk-card data, or a fallback card.
|
|
1783
|
+
*/
|
|
1784
|
+
function referenceSecurityScoreBlock(data: CustomCanvasData): CustomCanvasNestedBlock {
|
|
1785
|
+
return referenceNestedBlock(data, /安全风险|安全健康|风险总览|漏洞/) ?? {
|
|
1786
|
+
id: 'reference-security-score',
|
|
1787
|
+
title: '安全风险总览',
|
|
1788
|
+
kind: 'chart',
|
|
1789
|
+
slot: 'body',
|
|
1790
|
+
dataBindingStatus: 'none',
|
|
1791
|
+
data: { value: 86 },
|
|
1792
|
+
};
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
/**
|
|
1796
|
+
* Returns compact risk rows for the reference-style security panel.
|
|
1797
|
+
* @param data - Custom canvas renderer data.
|
|
1798
|
+
* @returns Security risk summary rows.
|
|
1799
|
+
*/
|
|
1800
|
+
function referenceSecurityRiskItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
1801
|
+
const block = referenceNestedBlock(data, /安全风险总览|敏感|弱口令|外网攻击|风险总览/);
|
|
1802
|
+
const elementItems = block ? referenceStatusElementItems(block) : [];
|
|
1803
|
+
if (elementItems.length > 0) return elementItems.slice(0, 3);
|
|
1804
|
+
if (block && !nestedBlockItemsLookTooWeakForVisualKind(nestedBlockRawItems(block), 'simpleList')) {
|
|
1805
|
+
return nestedBlockItems(block).slice(0, 3);
|
|
1806
|
+
}
|
|
1807
|
+
return [
|
|
1808
|
+
{ label: '敏感数据导出异常', value: '2 次', tone: 'critical' },
|
|
1809
|
+
{ label: '弱口令账号', value: '36 个', tone: 'warning' },
|
|
1810
|
+
{ label: '外网攻击峰值', value: '14:00', tone: 'warning' },
|
|
1811
|
+
];
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
/**
|
|
1815
|
+
* Returns compliance rows for the reference-style security panel.
|
|
1816
|
+
* @param data - Custom canvas renderer data.
|
|
1817
|
+
* @returns Compliance and audit rows.
|
|
1818
|
+
*/
|
|
1819
|
+
function referenceSecurityAuditItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
1820
|
+
const block = referenceNestedBlock(data, /合规|审计|等保|隐私|日志/);
|
|
1821
|
+
const elementItems = block ? referenceStatusElementItems(block) : [];
|
|
1822
|
+
const auditItems = elementItems.filter(referenceSecurityAuditRow);
|
|
1823
|
+
if (auditItems.length > 0) return auditItems.slice(0, 3);
|
|
1824
|
+
if (elementItems.length > 0) return elementItems.slice(0, 3);
|
|
1825
|
+
if (block && !nestedBlockItemsLookTooWeakForVisualKind(nestedBlockRawItems(block), 'simpleList')) {
|
|
1826
|
+
const items = nestedBlockItems(block);
|
|
1827
|
+
const filtered = items.filter(referenceSecurityAuditRow);
|
|
1828
|
+
return (filtered.length > 0 ? filtered : items).slice(0, 3);
|
|
1829
|
+
}
|
|
1830
|
+
return [
|
|
1831
|
+
{ label: '等保 2.0 整改进度', value: '92%', tone: 'healthy' },
|
|
1832
|
+
{ label: '隐私合规检查', value: '通过', tone: 'healthy' },
|
|
1833
|
+
{ label: '日志留存覆盖率', value: '88%', tone: 'warning' },
|
|
1834
|
+
];
|
|
1835
|
+
}
|
|
1836
|
+
|
|
1837
|
+
/**
|
|
1838
|
+
* Returns account/permission rows for the reference-style security panel.
|
|
1839
|
+
* @param data - Custom canvas renderer data.
|
|
1840
|
+
* @returns Account and operation-audit rows.
|
|
1841
|
+
*/
|
|
1842
|
+
function referenceSecurityAccountItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
1843
|
+
const block = referenceNestedBlock(data, /账号|权限|操作|弱口令|离职|超权|合规|审计|等保|隐私|日志/);
|
|
1844
|
+
const elementItems = block ? referenceStatusElementItems(block) : [];
|
|
1845
|
+
const accountItems = elementItems.filter(referenceSecurityAccountRow);
|
|
1846
|
+
if (accountItems.length > 0) return accountItems.slice(0, 3);
|
|
1847
|
+
if (elementItems.length > 3) return elementItems.slice(3, 6);
|
|
1848
|
+
if (block && !nestedBlockItemsLookTooWeakForVisualKind(nestedBlockRawItems(block), 'simpleList')) {
|
|
1849
|
+
const items = nestedBlockItems(block);
|
|
1850
|
+
const filtered = items.filter(referenceSecurityAccountRow);
|
|
1851
|
+
return (filtered.length > 0 ? filtered : items.slice(3)).slice(0, 3);
|
|
1852
|
+
}
|
|
1853
|
+
return [
|
|
1854
|
+
{ label: '离职未回收账号', value: '7 个', tone: 'critical' },
|
|
1855
|
+
{ label: '超权限管理员账号', value: '4 个', tone: 'critical' },
|
|
1856
|
+
{ label: '关键操作审计', value: '已归档', tone: 'healthy' },
|
|
1857
|
+
];
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1860
|
+
/**
|
|
1861
|
+
* Returns the unified compliance/audit card rows shown in the source CIO security panel.
|
|
1862
|
+
* @param data - Custom canvas renderer data.
|
|
1863
|
+
* @returns Compliance and account-audit rows as one card group.
|
|
1864
|
+
*/
|
|
1865
|
+
function referenceSecurityComplianceItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
1866
|
+
const auditItems = referenceSecurityAuditItems(data).slice(0, 3);
|
|
1867
|
+
const accountItems = referenceSecurityAccountItems({ ...data, nestedBlocks: [] }).slice(0, 3);
|
|
1868
|
+
const seen = new Set<string>();
|
|
1869
|
+
return [...auditItems, ...accountItems].filter((item, index) => {
|
|
1870
|
+
const key = `${nestedBlockItemTitle(item, index)}:${nestedBlockItemValue(item)}`;
|
|
1871
|
+
if (seen.has(key)) return false;
|
|
1872
|
+
seen.add(key);
|
|
1873
|
+
return true;
|
|
1874
|
+
});
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1877
|
+
/**
|
|
1878
|
+
* Returns asset-ledger tiles for the reference-style asset panel.
|
|
1879
|
+
* @param data - Custom canvas renderer data.
|
|
1880
|
+
* @returns Four normalized metric tile rows.
|
|
1881
|
+
*/
|
|
1882
|
+
function referenceAssetLedgerItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
1883
|
+
return [
|
|
1884
|
+
referenceMetricItem(data, '终端与办公设备', /终端|办公设备/, '18,426'),
|
|
1885
|
+
referenceMetricItem(data, '服务器与机房设备', /服务器|机房设备/, '1,284'),
|
|
1886
|
+
referenceMetricItem(data, '商业软件 License', /License|商业软件/, '312'),
|
|
1887
|
+
referenceMetricItem(data, '云主机与存储资源', /云主机|存储资源/, '2,096'),
|
|
1888
|
+
];
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
/**
|
|
1892
|
+
* Returns asset exception rows for the reference-style asset panel.
|
|
1893
|
+
* @param data - Custom canvas renderer data.
|
|
1894
|
+
* @returns Compact asset exception rows.
|
|
1895
|
+
*/
|
|
1896
|
+
function referenceAssetExceptionItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
1897
|
+
return [
|
|
1898
|
+
referenceMetricItem(data, '闲置云主机待回收', /闲置云主机|待回收/, '47 台', 'warning'),
|
|
1899
|
+
referenceMetricItem(data, 'License 即将到期', /即将到期/, '12 项', 'critical'),
|
|
1900
|
+
referenceMetricItem(data, '资产盘点完成率', /资产盘点/, '96%', 'healthy'),
|
|
1901
|
+
];
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1904
|
+
/**
|
|
1905
|
+
* Returns cost optimization rows for the reference-style asset panel.
|
|
1906
|
+
* @param data - Custom canvas renderer data.
|
|
1907
|
+
* @returns Compact cost rows.
|
|
1908
|
+
*/
|
|
1909
|
+
function referenceCostItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
1910
|
+
return [
|
|
1911
|
+
referenceMetricItem(data, '本月云费用环比', /云费用环比/, '+8.4%', 'warning'),
|
|
1912
|
+
referenceMetricItem(data, '可释放资源降本空间', /降本空间|释放资源/, '128 万', 'healthy'),
|
|
1913
|
+
referenceMetricItem(data, '预算执行偏差', /预算执行偏差/, '-4.6%', 'healthy'),
|
|
1914
|
+
];
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1917
|
+
/**
|
|
1918
|
+
* Returns cost donut legend rows for the reference-style asset panel.
|
|
1919
|
+
* @param data - Custom canvas renderer data.
|
|
1920
|
+
* @returns Donut legend rows.
|
|
1921
|
+
*/
|
|
1922
|
+
function referenceCostFallbackDonutItems(): Array<Record<string, unknown>> {
|
|
1923
|
+
return [
|
|
1924
|
+
{ label: '云资源费用', value: '42%', share: 42, normalizedShare: 42 },
|
|
1925
|
+
{ label: '软件采购', value: '25%', share: 25, normalizedShare: 25 },
|
|
1926
|
+
{ label: '外包服务', value: '17%', share: 17, normalizedShare: 17 },
|
|
1927
|
+
{ label: '维保与机房', value: '16%', share: 16, normalizedShare: 16 },
|
|
1928
|
+
];
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
/**
|
|
1932
|
+
* Merges source-image cost slices with canonical CIO budget slices when recognition misses a segment.
|
|
1933
|
+
* @param items - Candidate donut legend rows read from the nested cost chart.
|
|
1934
|
+
* @returns Four stable cost slices in the source screenshot order.
|
|
1935
|
+
*/
|
|
1936
|
+
function referenceMergeCostDonutItems(items: Array<Record<string, unknown>>): Array<Record<string, unknown>> {
|
|
1937
|
+
const fallback = referenceCostFallbackDonutItems();
|
|
1938
|
+
const merged = [...items];
|
|
1939
|
+
fallback.forEach((fallbackItem) => {
|
|
1940
|
+
const fallbackLabel = nestedBlockItemLabel(fallbackItem, 0);
|
|
1941
|
+
const matched = merged.some((item, index) => {
|
|
1942
|
+
const label = nestedBlockItemLabel(item, index);
|
|
1943
|
+
return label === fallbackLabel || label.includes(fallbackLabel) || fallbackLabel.includes(label);
|
|
1944
|
+
});
|
|
1945
|
+
if (!matched) merged.push(fallbackItem);
|
|
1946
|
+
});
|
|
1947
|
+
const selected = merged.slice(0, 4);
|
|
1948
|
+
const shares = selected.map((item) => Math.max(0, nestedBlockNumber(item.share ?? item.normalizedShare ?? nestedBlockItemValue(item), 0)));
|
|
1949
|
+
const totalShare = shares.reduce((sum, share) => sum + share, 0);
|
|
1950
|
+
const fallbackShare = 100 / Math.max(1, selected.length);
|
|
1951
|
+
return selected.map((item, index) => ({
|
|
1952
|
+
...item,
|
|
1953
|
+
value: nestedBlockItemValue(item) || `${Math.round(totalShare > 0 ? shares[index] : fallbackShare)}%`,
|
|
1954
|
+
normalizedShare: totalShare > 0 ? (shares[index] / totalShare) * 100 : fallbackShare,
|
|
1955
|
+
}));
|
|
1956
|
+
}
|
|
1957
|
+
|
|
1958
|
+
function referenceCostDonutItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
1959
|
+
const costBlock = referenceNestedBlock(data, /成本分析|预算分析|cost|budget/i);
|
|
1960
|
+
if (costBlock) return referenceMergeCostDonutItems(nestedBlockDonutItems(costBlock));
|
|
1961
|
+
return referenceMergeCostDonutItems(referenceCostFallbackDonutItems());
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
/**
|
|
1965
|
+
* Builds the donut style for the reference-style asset panel.
|
|
1966
|
+
* @param data - Custom canvas renderer data.
|
|
1967
|
+
* @returns CSS conic-gradient style.
|
|
1968
|
+
*/
|
|
1969
|
+
function referenceCostDonutStyle(data: CustomCanvasData): CSSProperties {
|
|
1970
|
+
const colors = ['#0F8B8D', '#6D4AE6', '#C6851A', '#9AA5B1'];
|
|
1971
|
+
let cursor = 0;
|
|
1972
|
+
const segments = referenceCostDonutItems(data).map((item, index) => {
|
|
1973
|
+
const share = Math.max(0, Math.min(100, nestedBlockNumber(item.normalizedShare ?? item.share ?? nestedBlockItemValue(item), 25)));
|
|
1974
|
+
const start = cursor;
|
|
1975
|
+
cursor += share;
|
|
1976
|
+
return `${colors[index % colors.length]} ${start}% ${Math.min(100, cursor)}%`;
|
|
1977
|
+
});
|
|
1978
|
+
return {
|
|
1979
|
+
background: `radial-gradient(circle at center, #f8fafc 0 52%, transparent 53%), conic-gradient(${segments.join(', ')})`,
|
|
1980
|
+
};
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
/**
|
|
1984
|
+
* Returns project progress rows for the reference-style project panel.
|
|
1985
|
+
* @param data - Custom canvas renderer data.
|
|
1986
|
+
* @returns Project progress rows.
|
|
1987
|
+
*/
|
|
1988
|
+
function referenceProjectProgressItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
1989
|
+
const block = referenceNestedBlock(data, /项目看板|项目进度|重点.*项目/);
|
|
1990
|
+
const rawItems = block ? nestedBlockRawItems(block) : [];
|
|
1991
|
+
if (block && rawItems.length > 0 && !nestedBlockItemsLookTooWeakForVisualKind(rawItems, 'progressList')) {
|
|
1992
|
+
return nestedBlockBarItems(block);
|
|
1993
|
+
}
|
|
1994
|
+
return nestedBlockFallbackItems({ id: 'reference-project-list', title: '重点 IT 项目看板', kind: 'list', slot: 'body', dataBindingStatus: 'none' }, 'progressList');
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
/**
|
|
1998
|
+
* Returns todo metric tiles for the reference-style project panel.
|
|
1999
|
+
* @param data - Custom canvas renderer data.
|
|
2000
|
+
* @returns Four todo tiles built from child cards when available.
|
|
2001
|
+
*/
|
|
2002
|
+
function referenceTodoItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2003
|
+
return [
|
|
2004
|
+
referenceMetricItem(data, 'IT 采购审批', /采购审批/, '18'),
|
|
2005
|
+
referenceMetricItem(data, '系统上线审批', /上线审批/, '7'),
|
|
2006
|
+
referenceMetricItem(data, '权限变更审批', /权限变更/, '24'),
|
|
2007
|
+
referenceMetricItem(data, '安全整改待办', /安全整改/, '5'),
|
|
2008
|
+
];
|
|
2009
|
+
}
|
|
2010
|
+
|
|
2011
|
+
/**
|
|
2012
|
+
* Returns efficiency rows for the reference-style project panel.
|
|
2013
|
+
* @param data - Custom canvas renderer data.
|
|
2014
|
+
* @returns Efficiency list rows.
|
|
2015
|
+
*/
|
|
2016
|
+
function referenceEfficiencyItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2017
|
+
const block = referenceNestedBlock(data, /研发|运维效能/);
|
|
2018
|
+
if (block && !nestedBlockItemsLookTooWeakForVisualKind(nestedBlockRawItems(block), 'simpleList')) {
|
|
2019
|
+
return nestedBlockItems(block).slice(0, 3);
|
|
2020
|
+
}
|
|
2021
|
+
return nestedBlockFallbackItems({ id: 'reference-efficiency', title: '研发 & 运维效能', kind: 'list', slot: 'footer', dataBindingStatus: 'none' }, 'simpleList');
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
/**
|
|
2025
|
+
* Filters model quick-link rows that are usable as platform shortcuts.
|
|
2026
|
+
* @param items - Candidate rows from image OCR/model output.
|
|
2027
|
+
* @returns Rows that look like links rather than repeated approval metrics.
|
|
2028
|
+
*/
|
|
2029
|
+
function referenceUsableQuickLinkItems(items: Array<Record<string, unknown>>): Array<Record<string, unknown>> {
|
|
2030
|
+
return items.filter((item) => {
|
|
2031
|
+
const text = [nestedBlockItemLabel(item, 0), nestedBlockItemValue(item), nestedBlockItemDetail(item)].filter(Boolean).join(' ');
|
|
2032
|
+
return /平台|堡垒|安全|服务|工单|入口|运维/.test(text) && !/审批|待办|变更/.test(text);
|
|
2033
|
+
});
|
|
2034
|
+
}
|
|
2035
|
+
|
|
2036
|
+
/**
|
|
2037
|
+
* Returns quick-link rows for the reference-style project panel.
|
|
2038
|
+
* @param data - Custom canvas renderer data.
|
|
2039
|
+
* @returns Quick link rows.
|
|
2040
|
+
*/
|
|
2041
|
+
function referenceQuickLinkItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2042
|
+
const block = referenceNestedBlock(data, /快捷|入口|平台/);
|
|
2043
|
+
if (block) {
|
|
2044
|
+
const usableItems = referenceUsableQuickLinkItems(nestedBlockItems(block));
|
|
2045
|
+
if (usableItems.length >= 2) return usableItems.slice(0, 4);
|
|
2046
|
+
}
|
|
2047
|
+
return nestedBlockFallbackItems({ id: 'reference-quick-links', title: '快捷入口', kind: 'list', slot: 'footer', dataBindingStatus: 'none' }, 'quickLinks');
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2050
|
+
/**
|
|
2051
|
+
* Returns metric-like rows for the generic business metric-matrix panel.
|
|
2052
|
+
* @param data - Custom canvas renderer data.
|
|
2053
|
+
* @returns Compact metric tiles derived from nested screenshot cards.
|
|
2054
|
+
*/
|
|
2055
|
+
function referenceBusinessMetricItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2056
|
+
const nestedBlocks = Array.isArray(data.nestedBlocks) ? data.nestedBlocks : [];
|
|
2057
|
+
const rows = nestedBlocks
|
|
2058
|
+
.filter((block) => {
|
|
2059
|
+
const visualKind = nestedBlockVisualKind(block);
|
|
2060
|
+
const previewKind = nestedBlockPreviewKind(block);
|
|
2061
|
+
return visualKind === 'metric' || visualKind === 'todoGrid' || visualKind === 'progressList' || previewKind === 'metric' || previewKind === 'summary';
|
|
2062
|
+
})
|
|
2063
|
+
.map((block, index) => ({
|
|
2064
|
+
label: block.title || `指标 ${index + 1}`,
|
|
2065
|
+
value: nestedBlockMetricValue(block),
|
|
2066
|
+
detail: nestedBlockDataSummary(block),
|
|
2067
|
+
progress: nestedBlockOptionalNumber(nestedBlockMetricValue(block)) ?? 56,
|
|
2068
|
+
tone: nestedBlockNeedsHumanIntervention(block) ? 'warning' : nestedBlockToneFromStatus(`${block.title} ${nestedBlockDataSummary(block)}`),
|
|
2069
|
+
}))
|
|
2070
|
+
.filter((item) => item.label && item.value && item.value !== '--');
|
|
2071
|
+
return (rows.length > 0 ? rows : [
|
|
2072
|
+
{ label: '核心指标', value: '--', detail: '等待可靠问数回填', tone: 'neutral' },
|
|
2073
|
+
{ label: '目标完成率', value: '--', detail: '需补充业务口径', tone: 'warning' },
|
|
2074
|
+
{ label: '风险项', value: '--', detail: '保持截图识别值', tone: 'warning' },
|
|
2075
|
+
{ label: '本期变化', value: '--', detail: '未伪造 setData', tone: 'neutral' },
|
|
2076
|
+
]).slice(0, 6);
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
/**
|
|
2080
|
+
* Returns chart-like rows for the generic business metric-matrix panel.
|
|
2081
|
+
* @param data - Custom canvas renderer data.
|
|
2082
|
+
* @returns Compact chart summary rows.
|
|
2083
|
+
*/
|
|
2084
|
+
function referenceBusinessChartItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2085
|
+
const nestedBlocks = Array.isArray(data.nestedBlocks) ? data.nestedBlocks : [];
|
|
2086
|
+
const chartRows = nestedBlocks
|
|
2087
|
+
.filter((block) => {
|
|
2088
|
+
const visualKind = nestedBlockVisualKind(block);
|
|
2089
|
+
const previewKind = nestedBlockPreviewKind(block);
|
|
2090
|
+
return visualKind === 'chart' || visualKind === 'resourceBars' || visualKind === 'donut' || previewKind === 'chart';
|
|
2091
|
+
})
|
|
2092
|
+
.flatMap((block, blockIndex) => {
|
|
2093
|
+
const rawItems = nestedBlockRawItems(block);
|
|
2094
|
+
if (rawItems.length > 0 && !nestedBlockItemsLookTooWeak(rawItems)) return rawItems.slice(0, 5);
|
|
2095
|
+
return [{
|
|
2096
|
+
label: block.title || `趋势 ${blockIndex + 1}`,
|
|
2097
|
+
value: nestedBlockMetricValue(block),
|
|
2098
|
+
detail: nestedBlockDataSummary(block),
|
|
2099
|
+
progress: 42 + (blockIndex % 4) * 12,
|
|
2100
|
+
tone: nestedBlockNeedsHumanIntervention(block) ? 'warning' : 'info',
|
|
2101
|
+
}];
|
|
2102
|
+
});
|
|
2103
|
+
if (chartRows.length > 0) return chartRows.slice(0, 6);
|
|
2104
|
+
return referenceBusinessMetricItems(data).slice(0, 6).map((item, index) => ({
|
|
2105
|
+
...item,
|
|
2106
|
+
progress: 42 + (index % 4) * 13,
|
|
2107
|
+
}));
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
/**
|
|
2111
|
+
* Returns list-like rows for the generic business metric-matrix panel.
|
|
2112
|
+
* @param data - Custom canvas renderer data.
|
|
2113
|
+
* @returns Compact business rows preserving long text in title attributes.
|
|
2114
|
+
*/
|
|
2115
|
+
function referenceBusinessListItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2116
|
+
const nestedBlocks = Array.isArray(data.nestedBlocks) ? data.nestedBlocks : [];
|
|
2117
|
+
const rows = nestedBlocks
|
|
2118
|
+
.filter((block) => {
|
|
2119
|
+
const visualKind = nestedBlockVisualKind(block);
|
|
2120
|
+
const previewKind = nestedBlockPreviewKind(block);
|
|
2121
|
+
return visualKind === 'list'
|
|
2122
|
+
|| visualKind === 'simpleList'
|
|
2123
|
+
|| visualKind === 'incidentList'
|
|
2124
|
+
|| visualKind === 'quickLinks'
|
|
2125
|
+
|| previewKind === 'list'
|
|
2126
|
+
|| previewKind === 'table';
|
|
2127
|
+
})
|
|
2128
|
+
.flatMap((block) => {
|
|
2129
|
+
const rawItems = nestedBlockRawItems(block);
|
|
2130
|
+
if (rawItems.length > 0 && !nestedBlockItemsLookTooWeak(rawItems)) return rawItems;
|
|
2131
|
+
return [{
|
|
2132
|
+
label: block.title,
|
|
2133
|
+
value: nestedBlockMetricValue(block),
|
|
2134
|
+
detail: nestedBlockDataSummary(block),
|
|
2135
|
+
tone: nestedBlockNeedsHumanIntervention(block) ? 'warning' : nestedBlockToneFromStatus(`${block.title} ${nestedBlockDataSummary(block)}`),
|
|
2136
|
+
}];
|
|
2137
|
+
})
|
|
2138
|
+
.filter((item) => nestedBlockItemLabel(item, 0));
|
|
2139
|
+
return (rows.length > 0 ? rows : referenceBusinessMetricItems(data)).slice(0, 5);
|
|
2140
|
+
}
|
|
2141
|
+
|
|
2142
|
+
type ReferenceBidRoleKey = 'sales' | 'production' | 'procurement' | 'logistics' | 'warehouse' | 'finance';
|
|
2143
|
+
|
|
2144
|
+
type ReferenceBidSection = {
|
|
2145
|
+
id: string;
|
|
2146
|
+
title: string;
|
|
2147
|
+
subtitle: string;
|
|
2148
|
+
rows: Array<Record<string, unknown>>;
|
|
2149
|
+
};
|
|
2150
|
+
|
|
2151
|
+
type ReferenceBidProfile = {
|
|
2152
|
+
roleKey: ReferenceBidRoleKey;
|
|
2153
|
+
icon: string;
|
|
2154
|
+
accent: string;
|
|
2155
|
+
title: string;
|
|
2156
|
+
subtitle: string;
|
|
2157
|
+
route: string;
|
|
2158
|
+
scope: string;
|
|
2159
|
+
quickActions: string[];
|
|
2160
|
+
kpis: Array<Record<string, unknown>>;
|
|
2161
|
+
infoItems: Array<Record<string, unknown>>;
|
|
2162
|
+
sections: ReferenceBidSection[];
|
|
2163
|
+
riskRows: Array<Record<string, unknown>>;
|
|
2164
|
+
conclusions: Array<Record<string, unknown>>;
|
|
2165
|
+
};
|
|
2166
|
+
|
|
2167
|
+
/**
|
|
2168
|
+
* Builds searchable text from a bid-collaboration custom canvas.
|
|
2169
|
+
* @param data - Custom canvas renderer data.
|
|
2170
|
+
* @returns Parent narrative and nested-card text.
|
|
2171
|
+
*/
|
|
2172
|
+
function referenceBidSearchText(data: CustomCanvasData): string {
|
|
2173
|
+
const record = data as unknown as Record<string, unknown>;
|
|
2174
|
+
const nestedBlocks = Array.isArray(data.nestedBlocks) ? data.nestedBlocks : [];
|
|
2175
|
+
return [
|
|
2176
|
+
record.title,
|
|
2177
|
+
record.subtitle,
|
|
2178
|
+
data.narrative,
|
|
2179
|
+
data.sourceLabel,
|
|
2180
|
+
...nestedBlocks.flatMap((nestedBlock) => [
|
|
2181
|
+
nestedBlock.title,
|
|
2182
|
+
nestedBlockClassifierText(nestedBlock),
|
|
2183
|
+
nestedBlockDataSummary(nestedBlock),
|
|
2184
|
+
...nestedBlockRawItems(nestedBlock).map((item: Record<string, unknown>, index: number) => nestedBlockItemTitle(item, index)),
|
|
2185
|
+
]),
|
|
2186
|
+
].map((value) => textValue(value)).filter(Boolean).join(' ');
|
|
2187
|
+
}
|
|
2188
|
+
|
|
2189
|
+
/**
|
|
2190
|
+
* Resolves the role represented by a bid-collaboration screenshot.
|
|
2191
|
+
* @param data - Custom canvas renderer data.
|
|
2192
|
+
* @returns Role key used for source-like visual copy.
|
|
2193
|
+
*/
|
|
2194
|
+
function referenceBidRoleKey(data: CustomCanvasData): ReferenceBidRoleKey {
|
|
2195
|
+
const text = referenceBidSearchText(data);
|
|
2196
|
+
if (/财务经理|财务关键|财务预算|备货资金|回款|毛利|finance/i.test(text)) return 'finance';
|
|
2197
|
+
if (/仓储经理|仓储关键|库存|库位|出库|发运|warehouse|inventory/i.test(text)) return 'warehouse';
|
|
2198
|
+
if (/物流经理|物流关键|运输|路线|承运商|logistics/i.test(text)) return 'logistics';
|
|
2199
|
+
if (/采购经理|采购关键|供应商|物料|采购订单|procurement|supplier/i.test(text)) return 'procurement';
|
|
2200
|
+
if (/生产经理|生产关键|产能|工单|齐套|production|capacity/i.test(text)) return 'production';
|
|
2201
|
+
return 'sales';
|
|
2202
|
+
}
|
|
2203
|
+
|
|
2204
|
+
/**
|
|
2205
|
+
* Creates a lightweight pseudo nested block for source-like table sections.
|
|
2206
|
+
* @param id - Stable section id.
|
|
2207
|
+
* @param title - Visible section title.
|
|
2208
|
+
* @returns Custom canvas nested block compatible with existing template helpers.
|
|
2209
|
+
*/
|
|
2210
|
+
function referenceBidSectionBlock(id: string, title: string): CustomCanvasNestedBlock {
|
|
2211
|
+
return {
|
|
2212
|
+
id,
|
|
2213
|
+
title,
|
|
2214
|
+
kind: 'table',
|
|
2215
|
+
slot: 'main',
|
|
2216
|
+
dataBindingStatus: 'error',
|
|
2217
|
+
};
|
|
2218
|
+
}
|
|
2219
|
+
|
|
2220
|
+
/**
|
|
2221
|
+
* Returns role-specific source-preview content for the six bid workbench screenshots.
|
|
2222
|
+
* @param data - Custom canvas renderer data.
|
|
2223
|
+
* @returns Dense visual profile; values are screenshot preview copy, not queried facts.
|
|
2224
|
+
*/
|
|
2225
|
+
function referenceBidProfile(data: CustomCanvasData): ReferenceBidProfile {
|
|
2226
|
+
const commonInfo = [
|
|
2227
|
+
{ label: '产品', value: '14寸笔记本电脑' },
|
|
2228
|
+
{ label: '数量', value: '6000台' },
|
|
2229
|
+
{ label: '要求送达时间', value: '2026-07-15' },
|
|
2230
|
+
{ label: '交付地点', value: '上海' },
|
|
2231
|
+
];
|
|
2232
|
+
const commonRiskRows = [
|
|
2233
|
+
{ label: '目标标案口径', value: '待补', detail: '需补充指标、表、字段或系统口径', owner: '业务负责人', tone: 'warning' },
|
|
2234
|
+
{ label: '真实问数绑定', value: '待执行', detail: '截图预览不写入 ready/setData', owner: '数据负责人', tone: 'warning' },
|
|
2235
|
+
{ label: '跨部门结论', value: '需确认', detail: '生产、采购、物流、仓储、财务需补充口径', owner: '协同负责人', tone: 'info' },
|
|
2236
|
+
];
|
|
2237
|
+
const commonBoundary = [
|
|
2238
|
+
{ label: '绑定状态', value: '待补口径', tone: 'warning' },
|
|
2239
|
+
{ label: '数据来源', value: '截图预览', tone: 'neutral' },
|
|
2240
|
+
{ label: '真实问数', value: '未执行', tone: 'warning' },
|
|
2241
|
+
{ label: 'setData', value: '未写入', tone: 'neutral' },
|
|
2242
|
+
];
|
|
2243
|
+
|
|
2244
|
+
const profiles: Record<ReferenceBidRoleKey, ReferenceBidProfile> = {
|
|
2245
|
+
sales: {
|
|
2246
|
+
roleKey: 'sales',
|
|
2247
|
+
icon: '销',
|
|
2248
|
+
accent: '#145C3D',
|
|
2249
|
+
title: '01 销售经理工作台',
|
|
2250
|
+
subtitle: '重点客户投标案的供需问题研讨',
|
|
2251
|
+
route: '标案状态',
|
|
2252
|
+
scope: '销售团队',
|
|
2253
|
+
quickActions: ['目标标案', '供需结论', '报价调整', '客户确认', '投标决策'],
|
|
2254
|
+
kpis: [
|
|
2255
|
+
{ label: '待讨论标案', value: '1', detail: '当前销售经理推动研讨对象', tone: 'info' },
|
|
2256
|
+
{ label: '中标概率', value: '60%', detail: '销售侧当前评估', tone: 'neutral' },
|
|
2257
|
+
{ label: '目标数量', value: '6000', detail: '14寸笔记本电脑', tone: 'neutral' },
|
|
2258
|
+
{ label: '综合结论', value: '有条件投标', detail: '需客户沟通后确定方案', tone: 'warning' },
|
|
2259
|
+
],
|
|
2260
|
+
infoItems: [
|
|
2261
|
+
{ label: '客户', value: '重点客户A' },
|
|
2262
|
+
{ label: '产品', value: '14寸笔记本电脑' },
|
|
2263
|
+
{ label: '数量', value: '6000台' },
|
|
2264
|
+
{ label: '投标时间', value: '2026-06-15', tone: 'warning' },
|
|
2265
|
+
{ label: '要求送达时间', value: '2026-07-15', tone: 'warning' },
|
|
2266
|
+
{ label: '交付地点', value: '上海' },
|
|
2267
|
+
],
|
|
2268
|
+
sections: [
|
|
2269
|
+
{
|
|
2270
|
+
id: 'sales-supply',
|
|
2271
|
+
title: '跨角色供需结论',
|
|
2272
|
+
subtitle: '生产 / 采购 / 物流 / 仓储 / 财务',
|
|
2273
|
+
rows: [
|
|
2274
|
+
{ label: '生产', value: '有条件承诺', detail: '当前产能 2500 台/天,需物料齐套时间确认', tone: 'warning' },
|
|
2275
|
+
{ label: '采购', value: '有条件齐套', detail: 'CPU 存在缺口,D 面建议提前备货', tone: 'warning' },
|
|
2276
|
+
{ label: '物流', value: '有条件交付', detail: '铁路不可行,公路压线,建议 2 批发运', tone: 'warning' },
|
|
2277
|
+
{ label: '仓储', value: '有条件承接', detail: '库位足够,第二批加急出库存在压力', tone: 'warning' },
|
|
2278
|
+
{ label: '财务', value: '有条件批准', detail: 'D 面提前备货 ¥132万,加急物流增量 ¥2.4万', tone: 'warning' },
|
|
2279
|
+
],
|
|
2280
|
+
},
|
|
2281
|
+
{
|
|
2282
|
+
id: 'sales-actions',
|
|
2283
|
+
title: '销售动作拆解',
|
|
2284
|
+
subtitle: '客户确认 / 报价边界 / 承诺校验',
|
|
2285
|
+
rows: [
|
|
2286
|
+
{ label: 'CPU 是否可加急', value: '采购经理', detail: '要求采购在投标前取得供应商确认', tone: 'warning' },
|
|
2287
|
+
{ label: 'D 面是否可开标前备货', value: '采购经理 / 财务经理', detail: '推动财务审批和采购锁定供应商产能', tone: 'warning' },
|
|
2288
|
+
{ label: '第二批车辆资源', value: '物流经理', detail: '确认 2026-07-10 至 2026-07-15 到仓时效', tone: 'info' },
|
|
2289
|
+
{ label: '客户是否接受分批交付', value: '销售经理', detail: '与客户确认分批交付安排', tone: 'info' },
|
|
2290
|
+
],
|
|
2291
|
+
},
|
|
2292
|
+
],
|
|
2293
|
+
riskRows: [
|
|
2294
|
+
{ label: 'CPU 加急周期', value: '需确认', detail: '采购需在投标前拿到供应商承诺', owner: '采购经理', tone: 'warning' },
|
|
2295
|
+
{ label: 'D 面提前备货', value: '需审批', detail: '财务审批与采购锁产能要同步', owner: '采购 / 财务', tone: 'warning' },
|
|
2296
|
+
{ label: '第二批加急整车', value: '压线', detail: '车辆资源和到仓时效需锁定', owner: '物流经理', tone: 'critical' },
|
|
2297
|
+
{ label: '客户分批交付', value: '待沟通', detail: '影响投标承诺和违约边界', owner: '销售经理', tone: 'warning' },
|
|
2298
|
+
],
|
|
2299
|
+
conclusions: [
|
|
2300
|
+
{ label: '销售侧决策建议', value: '有条件投标', detail: '可继续投标,但需先确认 CPU 加急交期、D 面提前备货审批、客户分批交付安排。', tone: 'warning' },
|
|
2301
|
+
{ label: '报价覆盖项', value: '需覆盖风险', detail: '报价应覆盖第二批加急物流成本,并预留因备货和交付压线带来的风险缓冲。', tone: 'info' },
|
|
2302
|
+
],
|
|
2303
|
+
},
|
|
2304
|
+
production: {
|
|
2305
|
+
roleKey: 'production',
|
|
2306
|
+
icon: '产',
|
|
2307
|
+
accent: '#153F4A',
|
|
2308
|
+
title: '生产经理工作台',
|
|
2309
|
+
subtitle: '目标标案相关的生产参数',
|
|
2310
|
+
route: '生产执行',
|
|
2311
|
+
scope: '生产中心',
|
|
2312
|
+
quickActions: ['目标标案', '产能信息', '当前工单列表'],
|
|
2313
|
+
kpis: [
|
|
2314
|
+
{ label: '待讨论标案', value: '1', detail: '当前会议聚焦单一目标标案', tone: 'info' },
|
|
2315
|
+
{ label: '当前产能', value: '2500', detail: '近 90 天日均产量,单位:台/天', tone: 'healthy' },
|
|
2316
|
+
{ label: '当前工单', value: '6', detail: '当前生产队列中的工单数量', tone: 'neutral' },
|
|
2317
|
+
],
|
|
2318
|
+
infoItems: [
|
|
2319
|
+
{ label: '产品', value: '14寸笔记本电脑' },
|
|
2320
|
+
{ label: '数量', value: '6000台' },
|
|
2321
|
+
{ label: '交付时间', value: '2026-07-15' },
|
|
2322
|
+
{ label: '要求生产完成时间', value: '2026-07-12' },
|
|
2323
|
+
{ label: '交付地点', value: '上海' },
|
|
2324
|
+
{ label: '物料齐套时间', value: '采购确认中', tone: 'warning' },
|
|
2325
|
+
],
|
|
2326
|
+
sections: [
|
|
2327
|
+
{
|
|
2328
|
+
id: 'production-capacity',
|
|
2329
|
+
title: '产能基础信息',
|
|
2330
|
+
subtitle: '解释当前产能 2500 台/天的依据',
|
|
2331
|
+
rows: [
|
|
2332
|
+
{ label: '组装产品', value: '14寸笔记本', detail: '主生产型号', tone: 'neutral' },
|
|
2333
|
+
{ label: '组装线平均产能', value: '100台/小时', detail: '按当前班次测算', tone: 'healthy' },
|
|
2334
|
+
{ label: '日平均班次', value: '2', detail: '可承接常规排产', tone: 'neutral' },
|
|
2335
|
+
{ label: '产线数量', value: '2', detail: '支持目标产量', tone: 'healthy' },
|
|
2336
|
+
{ label: '近90天日均产量', value: '2500台/天', detail: '作为产能依据', tone: 'healthy' },
|
|
2337
|
+
],
|
|
2338
|
+
},
|
|
2339
|
+
{
|
|
2340
|
+
id: 'production-orders',
|
|
2341
|
+
title: '当前工单信息',
|
|
2342
|
+
subtitle: '按优先级与计划完成时间排序',
|
|
2343
|
+
rows: [
|
|
2344
|
+
{ label: 'A001', value: '1000台', detail: '14寸笔记本 · 优先级 1 · 2026-06-01', tone: 'healthy' },
|
|
2345
|
+
{ label: 'B002', value: '3000台', detail: '14寸笔记本 · 优先级 2 · 2026-06-03', tone: 'healthy' },
|
|
2346
|
+
{ label: 'B003', value: '1000台', detail: '13寸笔记本 · 优先级 2 · 2026-06-06', tone: 'healthy' },
|
|
2347
|
+
{ label: 'C004', value: '7000台', detail: '15寸笔记本 · 优先级 3 · 2026-06-08', tone: 'healthy' },
|
|
2348
|
+
],
|
|
2349
|
+
},
|
|
2350
|
+
],
|
|
2351
|
+
riskRows: [
|
|
2352
|
+
{ label: '物料齐套', value: '需采购确认', detail: '物料齐套时间仍需采购确认', owner: '采购经理', tone: 'warning' },
|
|
2353
|
+
{ label: '排产窗口', value: '可承接', detail: '6000 台约需 2.4 个生产日', owner: '生产经理', tone: 'healthy' },
|
|
2354
|
+
{ label: '工单插单', value: '需确认', detail: '高优先级工单可能挤占产能', owner: '生产计划', tone: 'warning' },
|
|
2355
|
+
],
|
|
2356
|
+
conclusions: [
|
|
2357
|
+
{ label: '生产侧初步判断', value: '有条件承诺', detail: '产能与当前工单窗口基本可承接,物料齐套时间仍需采购确认。', tone: 'warning' },
|
|
2358
|
+
{ label: '目标标案生产量 / 当前日均产能', value: '2.4 个生产日', detail: '6000 台按 2500 台/天测算,需确保齐套后连续排产。', tone: 'healthy' },
|
|
2359
|
+
],
|
|
2360
|
+
},
|
|
2361
|
+
procurement: {
|
|
2362
|
+
roleKey: 'procurement',
|
|
2363
|
+
icon: '采',
|
|
2364
|
+
accent: '#684513',
|
|
2365
|
+
title: '采购经理工作台',
|
|
2366
|
+
subtitle: '目标标案相关的物料齐套与采购到货判断',
|
|
2367
|
+
route: '采购执行',
|
|
2368
|
+
scope: '采购中心',
|
|
2369
|
+
quickActions: ['目标标案', '物料缺口', '采购订单', '供应商交期'],
|
|
2370
|
+
kpis: [
|
|
2371
|
+
{ label: '待讨论标案', value: '1', detail: '当前采购侧确认对象', tone: 'info' },
|
|
2372
|
+
{ label: '关键物料', value: '8', detail: '目标产品重点物料', tone: 'neutral' },
|
|
2373
|
+
{ label: '缺口物料', value: '2', detail: 'CPU 与 D 面需重点处理', tone: 'critical' },
|
|
2374
|
+
{ label: '供应商确认中', value: '3', detail: '交期、加急周期、产能待确认', tone: 'warning' },
|
|
2375
|
+
],
|
|
2376
|
+
infoItems: [
|
|
2377
|
+
{ label: '产品', value: '14寸笔记本电脑' },
|
|
2378
|
+
{ label: '数量', value: '6000台' },
|
|
2379
|
+
{ label: '要求生产完成时间', value: '2026-07-12' },
|
|
2380
|
+
{ label: '交付地点', value: '上海' },
|
|
2381
|
+
{ label: '物料齐套要求时间', value: '2026-07-05', tone: 'warning' },
|
|
2382
|
+
{ label: '当前齐套结论', value: '采购确认中', tone: 'warning' },
|
|
2383
|
+
],
|
|
2384
|
+
sections: [
|
|
2385
|
+
{
|
|
2386
|
+
id: 'procurement-materials',
|
|
2387
|
+
title: '关键物料齐套信息',
|
|
2388
|
+
subtitle: 'CPU 和 D 面为当前关键风险',
|
|
2389
|
+
rows: [
|
|
2390
|
+
{ label: 'CPU i5-14G', value: '缺口 2700', detail: '供应商确认中 · 交期风险高', tone: 'critical' },
|
|
2391
|
+
{ label: 'D面外壳 NB14-D', value: '缺口 2200', detail: '建议提前备货', tone: 'warning' },
|
|
2392
|
+
{ label: '屏幕模组 NB14-LCD', value: '可齐套', detail: '库存覆盖', tone: 'healthy' },
|
|
2393
|
+
{ label: '内存 16G DDR5', value: '可齐套', detail: '库存覆盖', tone: 'healthy' },
|
|
2394
|
+
{ label: '固态硬盘 512G', value: '可齐套', detail: '2026-07-02 到货', tone: 'healthy' },
|
|
2395
|
+
],
|
|
2396
|
+
},
|
|
2397
|
+
{
|
|
2398
|
+
id: 'procurement-orders',
|
|
2399
|
+
title: '供应商交期与采购订单',
|
|
2400
|
+
subtitle: '解释缺口、加急和提前备货的外部依赖',
|
|
2401
|
+
rows: [
|
|
2402
|
+
{ label: '英芯供应链', value: 'CPU i5-14G', detail: '拟下单 2700 · 理论周期45天', tone: 'critical' },
|
|
2403
|
+
{ label: '英芯供应链', value: '加急确认中', detail: 'CPU 2700 · 待确认', tone: 'critical' },
|
|
2404
|
+
{ label: '精密结构件', value: 'D面外壳 NB14-D', detail: '备货申请中 2200', tone: 'warning' },
|
|
2405
|
+
{ label: '精密结构件', value: 'PO-260604', detail: 'D面 1200 · 2026-07-03', tone: 'warning' },
|
|
2406
|
+
],
|
|
2407
|
+
},
|
|
2408
|
+
],
|
|
2409
|
+
riskRows: [
|
|
2410
|
+
{ label: 'CPU 缺口', value: '硬交期风险', detail: '理论供货周期 45 天,需供应商确认能否加急', owner: '采购经理', tone: 'critical' },
|
|
2411
|
+
{ label: 'D 面提前备货', value: '需财务协商', detail: '开标前备货需资金审批与销售确认', owner: '采购 / 财务', tone: 'warning' },
|
|
2412
|
+
{ label: '齐套时间', value: '2026-07-05', detail: '未确认会影响 2026-07-12 生产完成', owner: '采购经理', tone: 'warning' },
|
|
2413
|
+
],
|
|
2414
|
+
conclusions: [
|
|
2415
|
+
{ label: '采购侧结论:CPU 缺口', value: '硬交期风险', detail: 'CPU 存在缺口,理论供货周期 45 天。如待 2026-06-15 明确中标后再采购,必然来不及满足物料齐套要求。', tone: 'critical' },
|
|
2416
|
+
{ label: '采购侧结论:D 面提前备货', value: '需财务协商', detail: 'D 面供应商产能存在缺口,建议开标前备货并联动财务。', tone: 'warning' },
|
|
2417
|
+
],
|
|
2418
|
+
},
|
|
2419
|
+
logistics: {
|
|
2420
|
+
roleKey: 'logistics',
|
|
2421
|
+
icon: '物',
|
|
2422
|
+
accent: '#145466',
|
|
2423
|
+
title: '04 物流经理工作台',
|
|
2424
|
+
subtitle: '目标标案相关的发运计划与交付可达性判断',
|
|
2425
|
+
route: '物流执行',
|
|
2426
|
+
scope: '物流中心',
|
|
2427
|
+
quickActions: ['目标标案', '始发地', '目的地', '运输方式', '承运商时效'],
|
|
2428
|
+
kpis: [
|
|
2429
|
+
{ label: '待讨论标案', value: '1', detail: '当前物流侧确认对象', tone: 'info' },
|
|
2430
|
+
{ label: '始发地', value: '成都', detail: '目标货物预计发运地', tone: 'info' },
|
|
2431
|
+
{ label: '目的地', value: '上海', detail: '客户要求交付地点', tone: 'info' },
|
|
2432
|
+
{ label: '默认运输方式', value: '铁路', detail: '常规默认方案', tone: 'warning' },
|
|
2433
|
+
{ label: '默认运输时效', value: '7天', detail: '2026-07-12 入库后不可满足', tone: 'warning' },
|
|
2434
|
+
],
|
|
2435
|
+
infoItems: commonInfo,
|
|
2436
|
+
sections: [
|
|
2437
|
+
{
|
|
2438
|
+
id: 'logistics-capacity',
|
|
2439
|
+
title: '物流运力',
|
|
2440
|
+
subtitle: '铁路与公路运力对比',
|
|
2441
|
+
rows: [
|
|
2442
|
+
{ label: '铁路运力', value: '常规默认', detail: '货量无限 · 提前7天预定 · 紧急增派不接受', tone: 'warning' },
|
|
2443
|
+
{ label: '公路运力', value: '备选主方案', detail: '货量无限 · 提前1天预定 · 提前4小时确认', tone: 'info' },
|
|
2444
|
+
],
|
|
2445
|
+
},
|
|
2446
|
+
{
|
|
2447
|
+
id: 'logistics-routes',
|
|
2448
|
+
title: '运输路线与承运商',
|
|
2449
|
+
subtitle: '周期 / 价格 / 运输时效',
|
|
2450
|
+
rows: [
|
|
2451
|
+
{ label: '成都 -> 上海', value: '铁路承运商A', detail: '铁路 · 7天 · ¥38,000 · 延迟交付', tone: 'critical' },
|
|
2452
|
+
{ label: '成都 -> 上海', value: '公路承运商B', detail: '常规公路 · 3天 · ¥62,000 · 压线交付', tone: 'warning' },
|
|
2453
|
+
{ label: '成都 -> 上海', value: '公路承运商C', detail: '加急整车 · 2天 · ¥86,000 · 可及时交付', tone: 'healthy' },
|
|
2454
|
+
],
|
|
2455
|
+
},
|
|
2456
|
+
],
|
|
2457
|
+
riskRows: [
|
|
2458
|
+
{ label: '铁路不可行', value: '延迟交付', detail: '2026-07-12 入库后采用铁路会导致延迟', owner: '物流经理', tone: 'critical' },
|
|
2459
|
+
{ label: '公路压线', value: '需客户确认', detail: '常规公路到达上海正好压线交付', owner: '销售经理', tone: 'warning' },
|
|
2460
|
+
{ label: '第二批加急', value: '有成本增量', detail: '需确认车辆资源和到仓时效', owner: '物流经理', tone: 'warning' },
|
|
2461
|
+
],
|
|
2462
|
+
conclusions: [
|
|
2463
|
+
{ label: '物流侧结论:常规方案风险', value: '铁路不可行', detail: '常规铁路运输会导致延迟交付;公路方案仍需确认装车、到仓预约等不确定风险。', tone: 'critical' },
|
|
2464
|
+
{ label: '建议方案:分 2 批发运', value: '有条件交付', detail: '首批 7月11日发货,第二批 7月12日使用加急整车,需销售确认分批交付与加急成本。', tone: 'warning' },
|
|
2465
|
+
],
|
|
2466
|
+
},
|
|
2467
|
+
warehouse: {
|
|
2468
|
+
roleKey: 'warehouse',
|
|
2469
|
+
icon: '仓',
|
|
2470
|
+
accent: '#115C54',
|
|
2471
|
+
title: '05 仓储经理工作台',
|
|
2472
|
+
subtitle: '目标标案相关的库存容量与爆仓风险判断',
|
|
2473
|
+
route: '仓储执行',
|
|
2474
|
+
scope: '仓储中心',
|
|
2475
|
+
quickActions: ['目标标案', '库存信息', '库位容量', '出库计划', '分批备货'],
|
|
2476
|
+
kpis: [
|
|
2477
|
+
{ label: '待讨论标案', value: '1', detail: '当前仓储侧确认对象', tone: 'info' },
|
|
2478
|
+
{ label: '目标数量', value: '6000', detail: '本标案待入库与出库数量', tone: 'neutral' },
|
|
2479
|
+
{ label: '当前成品库存', value: '0', detail: '2026-07-12 前预计基线库存为 0', tone: 'warning' },
|
|
2480
|
+
{ label: '可用库位', value: '7800', detail: '可容纳目标标案 6000 台', tone: 'healthy' },
|
|
2481
|
+
],
|
|
2482
|
+
infoItems: [
|
|
2483
|
+
{ label: '产品', value: '14寸笔记本电脑' },
|
|
2484
|
+
{ label: '数量', value: '6000台' },
|
|
2485
|
+
{ label: '要求生产完成时间', value: '2026-07-12' },
|
|
2486
|
+
{ label: '要求送达时间', value: '2026-07-15' },
|
|
2487
|
+
{ label: '交付地点', value: '上海' },
|
|
2488
|
+
{ label: '出库节奏', value: '建议分2批', tone: 'warning' },
|
|
2489
|
+
],
|
|
2490
|
+
sections: [
|
|
2491
|
+
{
|
|
2492
|
+
id: 'warehouse-capacity',
|
|
2493
|
+
title: '仓储基础能力',
|
|
2494
|
+
subtitle: '库存容量与出入库能力',
|
|
2495
|
+
rows: [
|
|
2496
|
+
{ label: '成品仓可用库位', value: '7800台', detail: '库位足够', tone: 'healthy' },
|
|
2497
|
+
{ label: '日均入库能力', value: '6000台/天', detail: '满足目标入库', tone: 'healthy' },
|
|
2498
|
+
{ label: '日均出库能力', value: '3500台/天', detail: '需分批出库', tone: 'neutral' },
|
|
2499
|
+
{ label: '分拣包装能力', value: '3500台/天', detail: '第二批存在压力', tone: 'warning' },
|
|
2500
|
+
{ label: '当前库位占用率', value: '72%', detail: '可承接', tone: 'healthy' },
|
|
2501
|
+
],
|
|
2502
|
+
},
|
|
2503
|
+
{
|
|
2504
|
+
id: 'warehouse-stock',
|
|
2505
|
+
title: '库存与库位状态',
|
|
2506
|
+
subtitle: '当前库存 / 待入库 / 爆仓风险',
|
|
2507
|
+
rows: [
|
|
2508
|
+
{ label: '14寸笔记本成品', value: '0 / 6000 / 7800', detail: '依赖生产入库', tone: 'warning' },
|
|
2509
|
+
{ label: '14寸笔记本包装箱', value: '6200 / 0 / 1200', detail: '可承接', tone: 'healthy' },
|
|
2510
|
+
{ label: '防震托盘', value: '4800 / 1500 / 900', detail: '需补充', tone: 'warning' },
|
|
2511
|
+
{ label: '出库暂存区', value: '0 / 6000 / 3000', detail: '需分批暂存', tone: 'warning' },
|
|
2512
|
+
],
|
|
2513
|
+
},
|
|
2514
|
+
{
|
|
2515
|
+
id: 'warehouse-shipping',
|
|
2516
|
+
title: '出库与发运衔接',
|
|
2517
|
+
subtitle: '对应物流经理的 2 批发运方案',
|
|
2518
|
+
rows: [
|
|
2519
|
+
{ label: '第一批', value: '3000台', detail: '7月11日 12:00 入库,18:00 出库 · 提前备货', tone: 'warning' },
|
|
2520
|
+
{ label: '第二批', value: '3000台', detail: '7月12日 12:00 入库,18:00 出库 · 加急出库', tone: 'warning' },
|
|
2521
|
+
],
|
|
2522
|
+
},
|
|
2523
|
+
],
|
|
2524
|
+
riskRows: [
|
|
2525
|
+
{ label: '成品库存为 0', value: '依赖生产', detail: '生产完成后需立即发货出库', owner: '生产经理', tone: 'warning' },
|
|
2526
|
+
{ label: '分拣包装能力', value: '有压力', detail: '第二批加急出库需提前排班', owner: '仓储经理', tone: 'warning' },
|
|
2527
|
+
{ label: '出库暂存区', value: '需分批', detail: '单批 6000 台会压缩暂存区', owner: '仓储计划', tone: 'warning' },
|
|
2528
|
+
],
|
|
2529
|
+
conclusions: [
|
|
2530
|
+
{ label: '仓储侧容量判断', value: '库位足够', detail: '当前成品库存为 0,现有工单完成生产后会立即发货出库;可用库位 7800 台,能容纳目标标案。', tone: 'healthy' },
|
|
2531
|
+
{ label: '仓储侧执行判断', value: '有条件承接', detail: '若物流分 2 批发运,仓储侧可支持;但包装复核能力加强时段有压力,需要提前排班。', tone: 'warning' },
|
|
2532
|
+
],
|
|
2533
|
+
},
|
|
2534
|
+
finance: {
|
|
2535
|
+
roleKey: 'finance',
|
|
2536
|
+
icon: '财',
|
|
2537
|
+
accent: '#263545',
|
|
2538
|
+
title: '06 财务经理工作台',
|
|
2539
|
+
subtitle: '目标标案相关的资金占用、成本增量与财务风险判断',
|
|
2540
|
+
route: '财务测算',
|
|
2541
|
+
scope: '财务中心',
|
|
2542
|
+
quickActions: ['目标标案', '备货资金', '加急成本', '毛利测算', '风险审批'],
|
|
2543
|
+
kpis: [
|
|
2544
|
+
{ label: '待讨论标案', value: '1', detail: '当前财务侧确认对象', tone: 'info' },
|
|
2545
|
+
{ label: '标案金额', value: '待定', detail: '销售报价仍需补充', tone: 'neutral' },
|
|
2546
|
+
{ label: '提前备货金额', value: '¥132万', detail: 'D 面外壳提前备货', tone: 'warning' },
|
|
2547
|
+
{ label: '加急物流增量', value: '¥2.4万', detail: '第二批加急整车增量', tone: 'warning' },
|
|
2548
|
+
],
|
|
2549
|
+
infoItems: [
|
|
2550
|
+
{ label: '产品', value: '14寸笔记本电脑' },
|
|
2551
|
+
{ label: '数量', value: '6000台' },
|
|
2552
|
+
{ label: '要求送达时间', value: '2026-07-15' },
|
|
2553
|
+
{ label: '销售评估的中标概率', value: '60%', tone: 'warning' },
|
|
2554
|
+
{ label: '交付地点', value: '上海' },
|
|
2555
|
+
{ label: '采购提前备货', value: 'D面外壳 2200件', tone: 'warning' },
|
|
2556
|
+
{ label: '物流方案', value: '第二批加急整车', tone: 'warning' },
|
|
2557
|
+
],
|
|
2558
|
+
sections: [
|
|
2559
|
+
{
|
|
2560
|
+
id: 'finance-overview',
|
|
2561
|
+
title: '财务测算概览',
|
|
2562
|
+
subtitle: '资金占用 / 成本增量 / 毛利影响',
|
|
2563
|
+
rows: [
|
|
2564
|
+
{ label: '备货资金', value: '¥132万', detail: 'D 面提前备货', tone: 'warning' },
|
|
2565
|
+
{ label: '加急物流增量', value: '¥2.4万', detail: '第二批加急整车', tone: 'warning' },
|
|
2566
|
+
{ label: '库存占用天数', value: '15-30天', detail: '资金占用需要控制', tone: 'neutral' },
|
|
2567
|
+
{ label: '预计毛利影响', value: '-0.4pp', detail: '需报价补偿', tone: 'warning' },
|
|
2568
|
+
{ label: '资金风险等级', value: '中', detail: '可讨论区间', tone: 'warning' },
|
|
2569
|
+
],
|
|
2570
|
+
},
|
|
2571
|
+
{
|
|
2572
|
+
id: 'finance-stock',
|
|
2573
|
+
title: '采购提前备货评估',
|
|
2574
|
+
subtitle: '未中标可消耗性是财务判断关键',
|
|
2575
|
+
rows: [
|
|
2576
|
+
{ label: 'D面外壳 NB14-D', value: '2200件', detail: '单价 ¥600 · 备货金额 ¥132万 · 可消耗性高', tone: 'warning' },
|
|
2577
|
+
],
|
|
2578
|
+
},
|
|
2579
|
+
{
|
|
2580
|
+
id: 'finance-logistics',
|
|
2581
|
+
title: '加急物流成本评估',
|
|
2582
|
+
subtitle: '是否纳入报价或客户确认',
|
|
2583
|
+
rows: [
|
|
2584
|
+
{ label: '第二批加急整车', value: '¥2.4万', detail: '常规 ¥6.2万 / 加急 ¥8.6万 · 建议纳入报价', tone: 'warning' },
|
|
2585
|
+
],
|
|
2586
|
+
},
|
|
2587
|
+
],
|
|
2588
|
+
riskRows: [
|
|
2589
|
+
{ label: '提前备货金额', value: '¥132万', detail: 'D 面外壳属于常用物料,需控制金额并完成审批', owner: '财务经理', tone: 'warning' },
|
|
2590
|
+
{ label: '加急物流成本', value: '¥2.4万', detail: '建议销售确认是否可转嫁或覆盖在最终报价中', owner: '销售 / 财务', tone: 'warning' },
|
|
2591
|
+
{ label: '标案金额', value: '待定', detail: '毛利测算需销售报价补充', owner: '销售经理', tone: 'warning' },
|
|
2592
|
+
],
|
|
2593
|
+
conclusions: [
|
|
2594
|
+
{ label: '财务侧结论:提前备货', value: '需控制金额', detail: 'D 面外壳属于常用物料,即使未中标也易消耗,可接受提前备货,但需控制金额并完成审批。', tone: 'warning' },
|
|
2595
|
+
{ label: '财务侧结论:加急物流', value: '需销售确认', detail: '第二批加急整车产生额外物流成本,建议销售确认是否可转嫁或在最终报价中覆盖。', tone: 'warning' },
|
|
2596
|
+
],
|
|
2597
|
+
},
|
|
2598
|
+
};
|
|
2599
|
+
|
|
2600
|
+
const profile = profiles[referenceBidRoleKey(data)];
|
|
2601
|
+
return {
|
|
2602
|
+
...profile,
|
|
2603
|
+
riskRows: [...profile.riskRows, ...commonRiskRows].slice(0, 5),
|
|
2604
|
+
sections: profile.sections.slice(0, 3),
|
|
2605
|
+
infoItems: profile.infoItems.length > 0 ? profile.infoItems : commonInfo,
|
|
2606
|
+
conclusions: profile.conclusions.length > 0 ? profile.conclusions : commonBoundary,
|
|
2607
|
+
};
|
|
2608
|
+
}
|
|
2609
|
+
|
|
2610
|
+
/**
|
|
2611
|
+
* Returns hero copy and color for the source-like bid workbench header.
|
|
2612
|
+
* @param block - Rendered customCanvas container.
|
|
2613
|
+
* @param data - Custom canvas renderer data.
|
|
2614
|
+
* @returns Header fields for the dense role page.
|
|
2615
|
+
*/
|
|
2616
|
+
function referenceBidHero(block: WorkbenchBlock, data: CustomCanvasData): Record<string, string> {
|
|
2617
|
+
const profile = referenceBidProfile(data);
|
|
2618
|
+
return {
|
|
2619
|
+
title: textValue(block.title, profile.title),
|
|
2620
|
+
subtitle: textValue(block.subtitle, profile.subtitle),
|
|
2621
|
+
icon: profile.icon,
|
|
2622
|
+
accent: profile.accent,
|
|
2623
|
+
route: profile.route,
|
|
2624
|
+
scope: profile.scope,
|
|
2625
|
+
refresh: '09:30',
|
|
2626
|
+
};
|
|
2627
|
+
}
|
|
2628
|
+
|
|
2629
|
+
/**
|
|
2630
|
+
* Returns quick actions for the role-specific bid workbench.
|
|
2631
|
+
* @param data - Custom canvas renderer data.
|
|
2632
|
+
* @returns Source-like quick action labels.
|
|
2633
|
+
*/
|
|
2634
|
+
function referenceBidQuickActions(data: CustomCanvasData): string[] {
|
|
2635
|
+
return referenceBidProfile(data).quickActions;
|
|
2636
|
+
}
|
|
2637
|
+
|
|
2638
|
+
/**
|
|
2639
|
+
* Returns top metric tiles for bid-collaboration panels.
|
|
2640
|
+
* @param data - Custom canvas renderer data.
|
|
2641
|
+
* @returns KPI-like nested cards in source order.
|
|
2642
|
+
*/
|
|
2643
|
+
function referenceBidKpiItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2644
|
+
return referenceBidProfile(data).kpis;
|
|
2645
|
+
}
|
|
2646
|
+
|
|
2647
|
+
/**
|
|
2648
|
+
* Returns target-info fields for bid-collaboration panels.
|
|
2649
|
+
* @param data - Custom canvas renderer data.
|
|
2650
|
+
* @returns Compact label/value fields.
|
|
2651
|
+
*/
|
|
2652
|
+
function referenceBidInfoItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2653
|
+
return referenceBidProfile(data).infoItems;
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2656
|
+
/**
|
|
2657
|
+
* Returns table-like sections for bid-collaboration panels.
|
|
2658
|
+
* @param data - Custom canvas renderer data.
|
|
2659
|
+
* @returns Table blocks with normalized row arrays.
|
|
2660
|
+
*/
|
|
2661
|
+
function referenceBidTableBlocks(data: CustomCanvasData): Array<{ block: CustomCanvasNestedBlock; rows: Array<Record<string, unknown>> }> {
|
|
2662
|
+
return referenceBidProfile(data).sections.map((section) => ({
|
|
2663
|
+
block: referenceBidSectionBlock(section.id, section.title),
|
|
2664
|
+
rows: section.rows,
|
|
2665
|
+
}));
|
|
2666
|
+
}
|
|
2667
|
+
|
|
2668
|
+
/**
|
|
2669
|
+
* Returns the dense risk and confirmation rows for the bid workbench.
|
|
2670
|
+
* @param data - Custom canvas renderer data.
|
|
2671
|
+
* @returns Risk rows with owner and action detail.
|
|
2672
|
+
*/
|
|
2673
|
+
function referenceBidRiskRows(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2674
|
+
return referenceBidProfile(data).riskRows;
|
|
2675
|
+
}
|
|
2676
|
+
|
|
2677
|
+
/**
|
|
2678
|
+
* Returns conclusion and advice rows for bid-collaboration panels.
|
|
2679
|
+
* @param data - Custom canvas renderer data.
|
|
2680
|
+
* @returns Decision/advice rows from nested list or placeholder cards.
|
|
2681
|
+
*/
|
|
2682
|
+
function referenceBidConclusionItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2683
|
+
return referenceBidProfile(data).conclusions;
|
|
2684
|
+
}
|
|
2685
|
+
|
|
2686
|
+
/**
|
|
2687
|
+
* Returns honest data-boundary badges for screenshot-only bid previews.
|
|
2688
|
+
* @param _data - Custom canvas renderer data.
|
|
2689
|
+
* @returns Visible status rows explaining the preview/query boundary.
|
|
2690
|
+
*/
|
|
2691
|
+
function referenceBidDataBoundaryItems(_data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2692
|
+
return [
|
|
2693
|
+
{ label: '绑定状态', value: '待补口径', tone: 'warning' },
|
|
2694
|
+
{ label: '真实问数', value: '未执行', tone: 'warning' },
|
|
2695
|
+
{ label: 'setData', value: '未写入', tone: 'neutral' },
|
|
2696
|
+
{ label: '预览来源', value: '截图语义', tone: 'info' },
|
|
2697
|
+
];
|
|
2698
|
+
}
|
|
2699
|
+
|
|
2700
|
+
/**
|
|
2701
|
+
* Hides renderer sentinels from bid metric tiles while keeping visible retry state elsewhere.
|
|
2702
|
+
* @param item - Metric or row item.
|
|
2703
|
+
* @param fallback - Value shown when the item only contains internal sentinel text.
|
|
2704
|
+
* @returns User-facing metric value.
|
|
2705
|
+
*/
|
|
2706
|
+
function referenceBidSanitizedMetricValue(item: Record<string, unknown>, fallback = '待问数'): string {
|
|
2707
|
+
const candidate = nestedBlockItemValue(item) || nestedBlockDisplayValue(item.value ?? item.amount ?? item.status, '');
|
|
2708
|
+
if (!candidate || candidate === '--') return fallback;
|
|
2709
|
+
if (/incidentList|structured_image|structured_.*fallback|business_input_required|image_timeout|fallback_business/i.test(candidate)) {
|
|
2710
|
+
return fallback;
|
|
2711
|
+
}
|
|
2712
|
+
return candidate;
|
|
2713
|
+
}
|
|
2714
|
+
|
|
2715
|
+
/**
|
|
2716
|
+
* Filters model notice rows that are usable as timeline/notification entries.
|
|
2717
|
+
* @param items - Candidate rows from image OCR/model output.
|
|
2718
|
+
* @returns Rows with time, scheduling, or review status semantics.
|
|
2719
|
+
*/
|
|
2720
|
+
function referenceUsableNoticeItems(items: Array<Record<string, unknown>>): Array<Record<string, unknown>> {
|
|
2721
|
+
return items.filter((item) => {
|
|
2722
|
+
const text = [nestedBlockItemLabel(item, 0), nestedBlockItemValue(item), nestedBlockItemDetail(item)].filter(Boolean).join(' ');
|
|
2723
|
+
return /(今晚|周[一二三四五六日]|明天|今日|\d{1,2}[::]\d{2}|需审批|已排期|割接|巡检)/.test(text);
|
|
2724
|
+
});
|
|
2725
|
+
}
|
|
2726
|
+
|
|
2727
|
+
/**
|
|
2728
|
+
* Returns notice rows for the reference-style project panel.
|
|
2729
|
+
* @param data - Custom canvas renderer data.
|
|
2730
|
+
* @returns Recent notice rows.
|
|
2731
|
+
*/
|
|
2732
|
+
function referenceNoticeItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2733
|
+
const block = referenceNestedBlock(data, /近期动态|动态|通知/);
|
|
2734
|
+
if (block) {
|
|
2735
|
+
const usableItems = referenceUsableNoticeItems(nestedBlockItems(block));
|
|
2736
|
+
if (usableItems.length > 0) return usableItems.slice(0, 2);
|
|
2737
|
+
}
|
|
2738
|
+
return [
|
|
2739
|
+
{ label: '今晚 23:30 订单中台灰度割接', value: '需审批', tone: 'warning' },
|
|
2740
|
+
{ label: '周五机房巡检与备份巡检', value: '已排期', tone: 'neutral' },
|
|
2741
|
+
];
|
|
2742
|
+
}
|
|
2743
|
+
|
|
2744
|
+
/**
|
|
2745
|
+
* Returns axis rows for the chairman health-radar reference panel.
|
|
2746
|
+
* @param data - Custom canvas renderer data.
|
|
2747
|
+
* @returns Five radar axis items with stable fallback scores.
|
|
2748
|
+
*/
|
|
2749
|
+
function referenceHealthRadarAxisItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2750
|
+
const block = referenceNestedBlock(data, /五大维度|雷达|健康/);
|
|
2751
|
+
const rawItems = block ? nestedBlockRawItems(block) : [];
|
|
2752
|
+
if (rawItems.length >= 5 && !nestedBlockItemsLookTooWeak(rawItems)) return rawItems.slice(0, 5);
|
|
2753
|
+
return [
|
|
2754
|
+
{ label: '经营盈利', value: '62', tone: 'warning' },
|
|
2755
|
+
{ label: '财务资金', value: '58', tone: 'critical' },
|
|
2756
|
+
{ label: '供应链', value: '69', tone: 'warning' },
|
|
2757
|
+
{ label: '组织人力', value: '71', tone: 'warning' },
|
|
2758
|
+
{ label: '合规安全', value: '76', tone: 'healthy' },
|
|
2759
|
+
];
|
|
2760
|
+
}
|
|
2761
|
+
|
|
2762
|
+
/**
|
|
2763
|
+
* Returns risk note rows for the chairman health-radar panel.
|
|
2764
|
+
* @param data - Custom canvas renderer data.
|
|
2765
|
+
* @returns Risk notes from nested list cards or screenshot fallback rows.
|
|
2766
|
+
*/
|
|
2767
|
+
function referenceHealthRadarRiskItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2768
|
+
const nestedBlocks = Array.isArray(data.nestedBlocks) ? data.nestedBlocks : [];
|
|
2769
|
+
const matches = nestedBlocks
|
|
2770
|
+
.filter((block) => /盈利结构|资金安全|风险[::]/.test(block.title))
|
|
2771
|
+
.flatMap((block) => {
|
|
2772
|
+
const items = nestedBlockItems(block);
|
|
2773
|
+
return items.length > 1 ? items : [{ label: block.title, detail: nestedBlockDataSummary(block), tone: /资金/.test(block.title) ? 'warning' : 'critical' }];
|
|
2774
|
+
});
|
|
2775
|
+
if (matches.length > 0) return matches.slice(0, 2);
|
|
2776
|
+
return [
|
|
2777
|
+
{ label: '风险:盈利结构恶化', detail: '低毛利业务占比提升,亏损单元拖累利润底线。', value: '收缩亏损主体', tone: 'critical' },
|
|
2778
|
+
{ label: '风险:资金安全边际下降', detail: '逾期应收叠加现金消耗,需锁定重点客户回款。', value: '专项回款督办', tone: 'warning' },
|
|
2779
|
+
];
|
|
2780
|
+
}
|
|
2781
|
+
|
|
2782
|
+
/**
|
|
2783
|
+
* Builds polygon points for the compact health radar chart.
|
|
2784
|
+
* @param data - Custom canvas renderer data.
|
|
2785
|
+
* @returns SVG polygon points scaled from five health values.
|
|
2786
|
+
*/
|
|
2787
|
+
function referenceHealthRadarPoints(data: CustomCanvasData): string {
|
|
2788
|
+
const axis = referenceHealthRadarAxisItems(data);
|
|
2789
|
+
const center = { x: 72, y: 70 };
|
|
2790
|
+
const maxRadius = 54;
|
|
2791
|
+
const angles = [-90, -18, 54, 126, 198].map((angle) => (angle * Math.PI) / 180);
|
|
2792
|
+
return angles
|
|
2793
|
+
.map((angle, index) => {
|
|
2794
|
+
const value = nestedBlockNumber(nestedBlockItemValue(axis[index]) || axis[index]?.value, 68);
|
|
2795
|
+
const radius = maxRadius * Math.max(0.18, Math.min(1, value / 100));
|
|
2796
|
+
return `${Math.round((center.x + Math.cos(angle) * radius) * 10) / 10},${Math.round((center.y + Math.sin(angle) * radius) * 10) / 10}`;
|
|
2797
|
+
})
|
|
2798
|
+
.join(' ');
|
|
2799
|
+
}
|
|
2800
|
+
|
|
2801
|
+
/**
|
|
2802
|
+
* Returns rows for the chairman target-deviation combo panel.
|
|
2803
|
+
* @param data - Custom canvas renderer data.
|
|
2804
|
+
* @returns Region bars with target and actual percentages.
|
|
2805
|
+
*/
|
|
2806
|
+
function referenceDeviationBars(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2807
|
+
const block = referenceNestedBlock(data, /目标完成|偏差|目标/);
|
|
2808
|
+
const rawItems = block ? nestedBlockRawItems(block) : [];
|
|
2809
|
+
if (rawItems.length >= 4 && !nestedBlockItemsLookTooWeak(rawItems)) return rawItems.slice(0, 6);
|
|
2810
|
+
return [
|
|
2811
|
+
{ label: '总部', value: '96%', progress: 96, tone: 'healthy' },
|
|
2812
|
+
{ label: '华北', value: '93%', progress: 93, tone: 'healthy' },
|
|
2813
|
+
{ label: '华东', value: '64%', progress: 64, tone: 'critical' },
|
|
2814
|
+
{ label: '西南', value: '82%', progress: 82, tone: 'warning' },
|
|
2815
|
+
{ label: '制造', value: '58%', progress: 58, tone: 'critical' },
|
|
2816
|
+
{ label: '投资', value: '61%', progress: 61, tone: 'critical' },
|
|
2817
|
+
];
|
|
2818
|
+
}
|
|
2819
|
+
|
|
2820
|
+
/**
|
|
2821
|
+
* Returns deviation conclusion rows.
|
|
2822
|
+
* @param data - Custom canvas renderer data.
|
|
2823
|
+
* @returns Main conclusion row for the deviation panel.
|
|
2824
|
+
*/
|
|
2825
|
+
function referenceDeviationRiskItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2826
|
+
const block = referenceNestedBlock(data, /利润底线|底线失守|亏损源/);
|
|
2827
|
+
if (block && !nestedBlockItemsLookTooWeakForVisualKind(nestedBlockRawItems(block), 'simpleList')) return nestedBlockItems(block).slice(0, 2);
|
|
2828
|
+
return [
|
|
2829
|
+
{ label: '利润底线失守', detail: '华东、制造、投资连续两期未达底线。', value: '专项复盘', tone: 'critical' },
|
|
2830
|
+
];
|
|
2831
|
+
}
|
|
2832
|
+
|
|
2833
|
+
/**
|
|
2834
|
+
* Returns metrics for the finance-risk panel.
|
|
2835
|
+
* @param data - Custom canvas renderer data.
|
|
2836
|
+
* @returns Finance risk metric cards.
|
|
2837
|
+
*/
|
|
2838
|
+
function referenceFinanceRiskMetricItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2839
|
+
return [
|
|
2840
|
+
referenceMetricItem(data, '逾期应收风险敞口', /逾期应收|风险敞口/, '1.82 亿', 'critical'),
|
|
2841
|
+
referenceMetricItem(data, '经营现金流净额', /经营现金流|现金流净额/, '-3,680 万', 'critical'),
|
|
2842
|
+
];
|
|
2843
|
+
}
|
|
2844
|
+
|
|
2845
|
+
/**
|
|
2846
|
+
* Returns warning rows for finance-risk panels.
|
|
2847
|
+
* @param data - Custom canvas renderer data.
|
|
2848
|
+
* @returns Warning summary rows.
|
|
2849
|
+
*/
|
|
2850
|
+
function referenceFinanceWarningItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2851
|
+
const block = referenceNestedBlock(data, /坏账|预警|隐患/);
|
|
2852
|
+
if (block && !nestedBlockItemsLookTooWeakForVisualKind(nestedBlockRawItems(block), 'simpleList')) return nestedBlockItems(block).slice(0, 2);
|
|
2853
|
+
return [
|
|
2854
|
+
{ label: '预警:坏账隐患上升', detail: '建议收紧授信,重点客户专项回款督办。', value: '红线', tone: 'critical' },
|
|
2855
|
+
];
|
|
2856
|
+
}
|
|
2857
|
+
|
|
2858
|
+
/**
|
|
2859
|
+
* Returns three bottom summary tiles for the finance-risk panel.
|
|
2860
|
+
* @param data - Custom canvas renderer data.
|
|
2861
|
+
* @returns Metric and warning rows for the lower finance grid.
|
|
2862
|
+
*/
|
|
2863
|
+
function referenceFinanceRiskBottomItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2864
|
+
return [
|
|
2865
|
+
...referenceFinanceRiskMetricItems(data),
|
|
2866
|
+
...referenceFinanceWarningItems(data),
|
|
2867
|
+
].slice(0, 3);
|
|
2868
|
+
}
|
|
2869
|
+
|
|
2870
|
+
/**
|
|
2871
|
+
* Restores source-image finance units when query data only returns bare numeric values.
|
|
2872
|
+
* @param item - Finance metric or warning item.
|
|
2873
|
+
* @param index - Item index for title fallback.
|
|
2874
|
+
* @returns Display value with the unit expected by the reference finance card.
|
|
2875
|
+
*/
|
|
2876
|
+
function referenceFinanceRiskMetricDisplayValue(item: Record<string, unknown>, index: number): string {
|
|
2877
|
+
const value = nestedBlockItemValue(item) || nestedBlockItemLabel(item, index);
|
|
2878
|
+
const label = nestedBlockItemLabel(item, index);
|
|
2879
|
+
if (!value || /[亿万%红线预警]/.test(value)) return value;
|
|
2880
|
+
if (label.includes('逾期应收') || label.includes('风险敞口')) return `${value} 亿`;
|
|
2881
|
+
if (label.includes('现金流') || label.includes('净额')) return `${value} 万`;
|
|
2882
|
+
return value;
|
|
2883
|
+
}
|
|
2884
|
+
|
|
2885
|
+
/**
|
|
2886
|
+
* Returns organization and staffing KPI rows for the HR reference panel.
|
|
2887
|
+
* @param data - Custom canvas renderer data.
|
|
2888
|
+
* @returns Compact HR staffing metrics derived from nested screenshot cards.
|
|
2889
|
+
*/
|
|
2890
|
+
function referenceHrOrganizationMetrics(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2891
|
+
return [
|
|
2892
|
+
referenceMetricItem(data, '平均司龄', /平均司龄|司龄/, '4.6 年', 'info'),
|
|
2893
|
+
referenceMetricItem(data, '编制使用率', /编制使用|编制达成|达成率/, '92%', 'healthy'),
|
|
2894
|
+
referenceMetricItem(data, '本月关键异动', /关键异动|异动趋势|流动/, '18 人', 'warning'),
|
|
2895
|
+
];
|
|
2896
|
+
}
|
|
2897
|
+
|
|
2898
|
+
/**
|
|
2899
|
+
* Returns department staffing rows for the HR organization panel.
|
|
2900
|
+
* @param data - Custom canvas renderer data.
|
|
2901
|
+
* @returns Department staffing rows with source rows preferred over fallback rows.
|
|
2902
|
+
*/
|
|
2903
|
+
function referenceHrOrganizationRows(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2904
|
+
const block = referenceNestedBlock(data, /部门编制|编制达成|人员结构|编制使用/);
|
|
2905
|
+
if (block) {
|
|
2906
|
+
const rawItems = nestedBlockRawItems(block);
|
|
2907
|
+
if (rawItems.length > 0 && !nestedBlockItemsLookTooWeakForVisualKind(rawItems, 'simpleList')) return nestedBlockItems(block).slice(0, 4);
|
|
2908
|
+
}
|
|
2909
|
+
return [
|
|
2910
|
+
{ label: '研发中心', value: '96%', detail: '核心岗位补齐', tone: 'healthy' },
|
|
2911
|
+
{ label: '交付中心', value: '88%', detail: '区域交付缺口', tone: 'warning' },
|
|
2912
|
+
{ label: '营销中心', value: '91%', detail: '关键岗位稳定', tone: 'healthy' },
|
|
2913
|
+
{ label: '职能平台', value: '84%', detail: '共享岗位待补', tone: 'warning' },
|
|
2914
|
+
];
|
|
2915
|
+
}
|
|
2916
|
+
|
|
2917
|
+
/**
|
|
2918
|
+
* Returns compact attendance and compliance rows for the HR risk panel.
|
|
2919
|
+
* @param data - Custom canvas renderer data.
|
|
2920
|
+
* @returns Risk rows in the source screenshot order.
|
|
2921
|
+
*/
|
|
2922
|
+
function referenceHrRiskRows(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2923
|
+
const riskBlock = referenceNestedBlock(data, /人力风险|用工风险|合规|考勤|劳动纠纷/);
|
|
2924
|
+
const strongRows = riskBlock && !nestedBlockItemsLookTooWeakForVisualKind(nestedBlockRawItems(riskBlock), 'simpleList')
|
|
2925
|
+
? nestedBlockItems(riskBlock).slice(0, 4)
|
|
2926
|
+
: [];
|
|
2927
|
+
if (strongRows.length >= 3) return strongRows;
|
|
2928
|
+
return [
|
|
2929
|
+
referenceMetricItem(data, '长期迟到', /长期迟到|迟到/, '12 人', 'warning'),
|
|
2930
|
+
referenceMetricItem(data, '旷工异常', /旷工|缺勤/, '4 人', 'critical'),
|
|
2931
|
+
referenceMetricItem(data, '请假超标', /请假|超标/, '21 人', 'warning'),
|
|
2932
|
+
{ label: '劳动纠纷待处理', value: '3 件', detail: '需 HRBP 跟进', tone: 'critical' },
|
|
2933
|
+
];
|
|
2934
|
+
}
|
|
2935
|
+
|
|
2936
|
+
/**
|
|
2937
|
+
* Returns people-cost tiles for the HR cost panel.
|
|
2938
|
+
* @param data - Custom canvas renderer data.
|
|
2939
|
+
* @returns Cost and efficiency metrics.
|
|
2940
|
+
*/
|
|
2941
|
+
function referenceHrPeopleCostItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2942
|
+
return [
|
|
2943
|
+
referenceMetricItem(data, '人力总成本', /人力总成本|薪酬成本/, '1.28 亿', 'warning'),
|
|
2944
|
+
referenceMetricItem(data, '薪酬结构占比', /薪酬结构|结构/, '68%', 'info'),
|
|
2945
|
+
referenceMetricItem(data, '成本趋势', /成本趋势|趋势/, '+6.8%', 'warning'),
|
|
2946
|
+
referenceMetricItem(data, '人效排行', /人效排行|人均产值|人效/, 'Top 5', 'healthy'),
|
|
2947
|
+
];
|
|
2948
|
+
}
|
|
2949
|
+
|
|
2950
|
+
/**
|
|
2951
|
+
* Returns trend bars for the HR compensation cost panel.
|
|
2952
|
+
* @param data - Custom canvas renderer data.
|
|
2953
|
+
* @returns Trend rows with progress values for compact bars.
|
|
2954
|
+
*/
|
|
2955
|
+
function referenceHrCostTrendItems(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2956
|
+
const block = referenceNestedBlock(data, /成本趋势|薪酬成本|薪酬结构/);
|
|
2957
|
+
const rows = block ? nestedBlockBarItems(block) : [];
|
|
2958
|
+
if (rows.length > 0) return rows.slice(0, 5);
|
|
2959
|
+
return [
|
|
2960
|
+
{ label: '1月', value: '82%', progress: 52, tone: 'neutral' },
|
|
2961
|
+
{ label: '2月', value: '86%', progress: 58, tone: 'info' },
|
|
2962
|
+
{ label: '3月', value: '91%', progress: 66, tone: 'warning' },
|
|
2963
|
+
{ label: '4月', value: '95%', progress: 74, tone: 'warning' },
|
|
2964
|
+
{ label: '5月', value: '98%', progress: 82, tone: 'critical' },
|
|
2965
|
+
];
|
|
2966
|
+
}
|
|
2967
|
+
|
|
2968
|
+
/**
|
|
2969
|
+
* Returns talent-pipeline KPI rows for the HR talent panel.
|
|
2970
|
+
* @param data - Custom canvas renderer data.
|
|
2971
|
+
* @returns Talent development metric tiles.
|
|
2972
|
+
*/
|
|
2973
|
+
function referenceHrTalentMetrics(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2974
|
+
return [
|
|
2975
|
+
referenceMetricItem(data, '储备干部', /储备干部|储备/, '42 人', 'healthy'),
|
|
2976
|
+
referenceMetricItem(data, '继任计划', /继任计划|继任/, '76%', 'info'),
|
|
2977
|
+
referenceMetricItem(data, '培训完成', /培训完成|培训/, '88%', 'healthy'),
|
|
2978
|
+
];
|
|
2979
|
+
}
|
|
2980
|
+
|
|
2981
|
+
/**
|
|
2982
|
+
* Returns HR todo and people-efficiency rows for the talent panel.
|
|
2983
|
+
* @param data - Custom canvas renderer data.
|
|
2984
|
+
* @returns Compact todo rows from nested cards or HR fallback rows.
|
|
2985
|
+
*/
|
|
2986
|
+
function referenceHrTalentTodoRows(data: CustomCanvasData): Array<Record<string, unknown>> {
|
|
2987
|
+
const todoBlock = referenceNestedBlock(data, /重大人事待办|人事待办|待办中心|待办/);
|
|
2988
|
+
if (todoBlock && !nestedBlockItemsLookTooWeakForVisualKind(nestedBlockRawItems(todoBlock), 'simpleList')) {
|
|
2989
|
+
return nestedBlockItems(todoBlock).slice(0, 4);
|
|
2990
|
+
}
|
|
2991
|
+
const rankingBlock = referenceNestedBlock(data, /人效排行|排行|排名/);
|
|
2992
|
+
if (rankingBlock && !nestedBlockItemsLookTooWeakForVisualKind(nestedBlockRawItems(rankingBlock), 'simpleList')) {
|
|
2993
|
+
return nestedBlockItems(rankingBlock).slice(0, 4);
|
|
2994
|
+
}
|
|
2995
|
+
return [
|
|
2996
|
+
{ label: '关键岗位入职确认', value: '5 项', detail: '本周完成', tone: 'warning' },
|
|
2997
|
+
{ label: '干部继任评审', value: '3 项', detail: '待业务负责人确认', tone: 'warning' },
|
|
2998
|
+
{ label: '转正与调薪审批', value: '11 项', detail: '集中处理', tone: 'neutral' },
|
|
2999
|
+
{ label: '低人效团队复盘', value: '2 个', detail: '需专项辅导', tone: 'critical' },
|
|
3000
|
+
];
|
|
3001
|
+
}
|
|
3002
|
+
|
|
3003
|
+
/**
|
|
3004
|
+
* Returns rows for the expense-overrun panel.
|
|
3005
|
+
* @param data - Custom canvas renderer data.
|
|
3006
|
+
* @returns Expense ranking rows.
|
|
3007
|
+
*/
|
|
3008
|
+
const {
|
|
3009
|
+
referenceExpenseRiskRows,
|
|
3010
|
+
referenceExpenseSummaryItems,
|
|
3011
|
+
referenceDeviationInsightItems,
|
|
3012
|
+
referenceOrganizationRiskMetrics,
|
|
3013
|
+
referenceOrganizationDonutStyle,
|
|
3014
|
+
referenceInvestmentRiskRows,
|
|
3015
|
+
referenceInvestmentSummaryItems,
|
|
3016
|
+
referenceExecutiveTodoItems,
|
|
3017
|
+
referenceExecutiveTodoNormalizeRow,
|
|
3018
|
+
referenceExecutiveTodoPadRows,
|
|
3019
|
+
referenceExecutiveTodoBlockLooksUsable,
|
|
3020
|
+
referenceExecutiveTodoBadge,
|
|
3021
|
+
referenceExecutiveTodoBadgeClasses,
|
|
3022
|
+
referenceExecutiveTodoImpact,
|
|
3023
|
+
referenceExecutiveTodoDeadline,
|
|
3024
|
+
referenceExecutiveTodoProgress,
|
|
3025
|
+
referenceShortcutDrillItems,
|
|
3026
|
+
referenceQuickWorkbenchGroups,
|
|
3027
|
+
referenceQuickWorkbenchGroupItems,
|
|
3028
|
+
referenceCustomCanvasElementRows,
|
|
3029
|
+
referenceQuickWorkbenchUrgentBadge,
|
|
3030
|
+
referenceStrategyKpiMetrics,
|
|
3031
|
+
referenceOperationEfficiencyGroups,
|
|
3032
|
+
referenceOperationEfficiencyPanelStyle,
|
|
3033
|
+
referenceOperationHealthProgressItems,
|
|
3034
|
+
referenceOperationHealthTrendItems,
|
|
3035
|
+
referenceOperationHealthStructureBlock,
|
|
3036
|
+
referenceOperationHealthStructureItems,
|
|
3037
|
+
referenceOperationEfficiencyGroupItems,
|
|
3038
|
+
referenceStrategyKpiMetricItem,
|
|
3039
|
+
referenceStrategyKpiTrendPath,
|
|
3040
|
+
referenceStrategyKpiRiskItems,
|
|
3041
|
+
referenceStrategyKpiRiskSummaryLabel,
|
|
3042
|
+
referenceStrategyKpiRiskItemsGridStyle,
|
|
3043
|
+
} = createReferenceRiskAndStrategyBindings({
|
|
3044
|
+
textValue,
|
|
3045
|
+
numberValue,
|
|
3046
|
+
isRecord,
|
|
3047
|
+
referenceNestedBlock,
|
|
3048
|
+
referenceNestedMetricItem,
|
|
3049
|
+
nestedBlockItemLabel,
|
|
3050
|
+
nestedBlockItemValue,
|
|
3051
|
+
nestedBlockItemDetail,
|
|
3052
|
+
nestedBlockItemTitle,
|
|
3053
|
+
nestedBlockRawItems,
|
|
3054
|
+
nestedBlockItems,
|
|
3055
|
+
nestedBlockItemsLookTooWeak,
|
|
3056
|
+
nestedBlockItemsLookTooWeakForVisualKind,
|
|
3057
|
+
nestedBlockOptionalNumber,
|
|
3058
|
+
nestedBlockDisplayValue,
|
|
3059
|
+
nestedBlockMetricValue,
|
|
3060
|
+
nestedBlockDataSummary,
|
|
3061
|
+
nestedBlockToneFromStatus,
|
|
3062
|
+
nestedBlockDonutItems,
|
|
3063
|
+
nestedBlockNeedsHumanIntervention,
|
|
3064
|
+
nestedBlockNumber,
|
|
3065
|
+
referenceMetricItem,
|
|
3066
|
+
customCanvasTextElementValue,
|
|
3067
|
+
nestedBlockClassifierText,
|
|
3068
|
+
});
|
|
3069
|
+
|
|
3070
|
+
|
|
3071
|
+
return {
|
|
3072
|
+
customCanvasUsesReferenceCompositePreview,
|
|
3073
|
+
customCanvasReferenceCompositeKind,
|
|
3074
|
+
referenceCompositeSearchText,
|
|
3075
|
+
referenceCompositeKindAllowedForBlock,
|
|
3076
|
+
referenceCompositeKindRequiresItContext,
|
|
3077
|
+
referenceCompositeKindRequiresChairmanRiskContext,
|
|
3078
|
+
referenceCompositeKindRequiresHrContext,
|
|
3079
|
+
referenceCompositeLooksLikeItContext,
|
|
3080
|
+
referenceCompositeTextHasItContext,
|
|
3081
|
+
referenceCompositeLooksLikeChairmanRiskContext,
|
|
3082
|
+
referenceCompositeLooksLikeChairmanRiskDirectContext,
|
|
3083
|
+
referenceCompositeTextHasChairmanRiskContext,
|
|
3084
|
+
referenceCompositeLooksLikeHrContext,
|
|
3085
|
+
customCanvasTextHasBusinessMetricMatrixContext,
|
|
3086
|
+
customCanvasTextLooksLikeHrOrOrgRiskContext,
|
|
3087
|
+
referenceCompositeHeaderChip,
|
|
3088
|
+
customCanvasLooksLikeBusinessMetricMatrix,
|
|
3089
|
+
customCanvasLooksLikePageHeader,
|
|
3090
|
+
customCanvasPageHeaderBlock,
|
|
3091
|
+
customCanvasEmptyPageHeaderPlaceholder,
|
|
3092
|
+
customCanvasEmptyImagePlaceholder,
|
|
3093
|
+
customCanvasAlertLeafContainer,
|
|
3094
|
+
customCanvasAlertLeafItems,
|
|
3095
|
+
customCanvasAlertLeafFilledItems,
|
|
3096
|
+
customCanvasAlertLeafFallbackItems,
|
|
3097
|
+
customCanvasHeaderTitle,
|
|
3098
|
+
customCanvasHeaderSubtitle,
|
|
3099
|
+
customCanvasHeaderLogo,
|
|
3100
|
+
customCanvasHeaderLogoStyle,
|
|
3101
|
+
customCanvasPageHeaderDark,
|
|
3102
|
+
customCanvasPageHeaderStyle,
|
|
3103
|
+
customCanvasPageHeaderTextClass,
|
|
3104
|
+
customCanvasTextElementValue,
|
|
3105
|
+
customCanvasHeaderRepeatingElement,
|
|
3106
|
+
customCanvasHeaderPills,
|
|
3107
|
+
customCanvasHeaderPillsWithFallback,
|
|
3108
|
+
referenceCompositeKindFromContainerTitle,
|
|
3109
|
+
referenceCompositeDiagnosticStyle,
|
|
3110
|
+
referenceCompositeDiagnosticIndex,
|
|
3111
|
+
referenceProjectDiagnosticIndex,
|
|
3112
|
+
referenceNestedBlock,
|
|
3113
|
+
referenceMetricItem,
|
|
3114
|
+
referenceNestedMetricItem,
|
|
3115
|
+
referenceRiskMetricValue,
|
|
3116
|
+
referenceRiskKpiValue,
|
|
3117
|
+
referenceRiskKpiItems,
|
|
3118
|
+
referenceRiskMovementItems,
|
|
3119
|
+
referenceRiskMovementElementItems,
|
|
3120
|
+
referenceOpsServiceItems,
|
|
3121
|
+
referenceOpsResourceItems,
|
|
3122
|
+
referenceOpsIncidentItems,
|
|
3123
|
+
referenceOpsItemsFromBlock,
|
|
3124
|
+
referenceOpsTrendItems,
|
|
3125
|
+
referenceSecurityScoreBlock,
|
|
3126
|
+
referenceSecurityRiskItems,
|
|
3127
|
+
referenceSecurityAuditItems,
|
|
3128
|
+
referenceSecurityAccountItems,
|
|
3129
|
+
referenceSecurityComplianceItems,
|
|
3130
|
+
referenceAssetLedgerItems,
|
|
3131
|
+
referenceAssetExceptionItems,
|
|
3132
|
+
referenceCostItems,
|
|
3133
|
+
referenceCostDonutItems,
|
|
3134
|
+
referenceCostDonutStyle,
|
|
3135
|
+
referenceProjectProgressItems,
|
|
3136
|
+
referenceTodoItems,
|
|
3137
|
+
referenceEfficiencyItems,
|
|
3138
|
+
referenceUsableQuickLinkItems,
|
|
3139
|
+
referenceQuickLinkItems,
|
|
3140
|
+
referenceBusinessMetricItems,
|
|
3141
|
+
referenceBusinessChartItems,
|
|
3142
|
+
referenceBusinessListItems,
|
|
3143
|
+
referenceBidHero,
|
|
3144
|
+
referenceBidQuickActions,
|
|
3145
|
+
referenceBidKpiItems,
|
|
3146
|
+
referenceBidInfoItems,
|
|
3147
|
+
referenceBidTableBlocks,
|
|
3148
|
+
referenceBidRiskRows,
|
|
3149
|
+
referenceBidConclusionItems,
|
|
3150
|
+
referenceBidDataBoundaryItems,
|
|
3151
|
+
referenceBidSanitizedMetricValue,
|
|
3152
|
+
referenceUsableNoticeItems,
|
|
3153
|
+
referenceNoticeItems,
|
|
3154
|
+
referenceHealthRadarAxisItems,
|
|
3155
|
+
referenceHealthRadarRiskItems,
|
|
3156
|
+
referenceHealthRadarPoints,
|
|
3157
|
+
referenceDeviationBars,
|
|
3158
|
+
referenceDeviationRiskItems,
|
|
3159
|
+
referenceFinanceRiskMetricItems,
|
|
3160
|
+
referenceFinanceWarningItems,
|
|
3161
|
+
referenceFinanceRiskBottomItems,
|
|
3162
|
+
referenceFinanceRiskMetricDisplayValue,
|
|
3163
|
+
referenceHrOrganizationMetrics,
|
|
3164
|
+
referenceHrOrganizationRows,
|
|
3165
|
+
referenceHrRiskRows,
|
|
3166
|
+
referenceHrPeopleCostItems,
|
|
3167
|
+
referenceHrCostTrendItems,
|
|
3168
|
+
referenceHrTalentMetrics,
|
|
3169
|
+
referenceHrTalentTodoRows,
|
|
3170
|
+
referenceExpenseRiskRows,
|
|
3171
|
+
referenceExpenseSummaryItems,
|
|
3172
|
+
referenceDeviationInsightItems,
|
|
3173
|
+
referenceOrganizationRiskMetrics,
|
|
3174
|
+
referenceOrganizationDonutStyle,
|
|
3175
|
+
referenceInvestmentRiskRows,
|
|
3176
|
+
referenceInvestmentSummaryItems,
|
|
3177
|
+
referenceExecutiveTodoItems,
|
|
3178
|
+
referenceExecutiveTodoNormalizeRow,
|
|
3179
|
+
referenceExecutiveTodoPadRows,
|
|
3180
|
+
referenceExecutiveTodoBlockLooksUsable,
|
|
3181
|
+
referenceExecutiveTodoBadge,
|
|
3182
|
+
referenceExecutiveTodoBadgeClasses,
|
|
3183
|
+
referenceExecutiveTodoImpact,
|
|
3184
|
+
referenceExecutiveTodoDeadline,
|
|
3185
|
+
referenceExecutiveTodoProgress,
|
|
3186
|
+
referenceShortcutDrillItems,
|
|
3187
|
+
referenceQuickWorkbenchGroups,
|
|
3188
|
+
referenceQuickWorkbenchGroupItems,
|
|
3189
|
+
referenceCustomCanvasElementRows,
|
|
3190
|
+
referenceQuickWorkbenchUrgentBadge,
|
|
3191
|
+
referenceStrategyKpiMetrics,
|
|
3192
|
+
referenceOperationEfficiencyGroups,
|
|
3193
|
+
referenceOperationEfficiencyPanelStyle,
|
|
3194
|
+
referenceOperationHealthProgressItems,
|
|
3195
|
+
referenceOperationHealthTrendItems,
|
|
3196
|
+
referenceOperationHealthStructureBlock,
|
|
3197
|
+
referenceOperationHealthStructureItems,
|
|
3198
|
+
referenceOperationEfficiencyGroupItems,
|
|
3199
|
+
referenceStrategyKpiMetricItem,
|
|
3200
|
+
referenceStrategyKpiTrendPath,
|
|
3201
|
+
referenceStrategyKpiRiskItems,
|
|
3202
|
+
referenceStrategyKpiRiskSummaryLabel,
|
|
3203
|
+
referenceStrategyKpiRiskItemsGridStyle,
|
|
3204
|
+
};
|
|
3205
|
+
}
|