@fses/workbench-app 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/WORKBENCH-CLOSURE.json +80 -0
- package/dist/Workspace-fYH2XNdb.js +22699 -0
- package/dist/fses-workbench-app.js +2 -2
- package/dist/{index-DbH6tMQy.js → index-CbIJlts1.js} +8 -8
- package/dist/internal/personal-workbench/components/workbench/WorkbenchStudio.vue.d.ts +2 -2
- package/dist/internal/personal-workbench/lib/deepAgentApi.d.ts +41 -2
- package/dist/internal/personal-workbench/lib/deepAgentQueueState.d.ts +111 -0
- package/dist/internal/personal-workbench/lib/vueRuntimeAdapters.d.ts +72 -0
- package/dist/internal/personal-workbench/lib/workbenchSocketClient.d.ts +1 -1
- package/dist/internal/personal-workbench/lib/workbenchStorage.d.ts +2 -0
- package/dist/runtime/index.js +1 -1
- package/dist/style.css +1 -1
- package/dist/{useWorkbenchRuntime-XpOzwm56.js → useWorkbenchRuntime-Ch8lqkjO.js} +6707 -6315
- 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 +33742 -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 +2011 -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 +83 -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.js +19950 -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 +1096 -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 +3209 -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 +2496 -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 +99 -104
- package/dist/Workspace-DMye5DU8.js +0 -43113
|
@@ -0,0 +1,2728 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview 工作台卡片运行时渲染器 - 根据卡片数据协议渲染图表、指标、表格和占位卡交互
|
|
3
|
+
* @author seadon
|
|
4
|
+
* @created 2026-05-10
|
|
5
|
+
*/
|
|
6
|
+
<script setup lang="ts">
|
|
7
|
+
import { Table as ATable } from 'ant-design-vue';
|
|
8
|
+
import {
|
|
9
|
+
ArrowRight,
|
|
10
|
+
CalendarDays,
|
|
11
|
+
CircleCheck,
|
|
12
|
+
ClipboardCheck,
|
|
13
|
+
CloudRain,
|
|
14
|
+
Droplets,
|
|
15
|
+
FileBarChart2,
|
|
16
|
+
Play,
|
|
17
|
+
Send,
|
|
18
|
+
Sparkles,
|
|
19
|
+
ThermometerSun,
|
|
20
|
+
Wind,
|
|
21
|
+
} from 'lucide-vue-next';
|
|
22
|
+
import ChartRegistryRenderer from './chart/ChartRegistry.vue';
|
|
23
|
+
import EChartsProtocolRenderer from './chart/EChartsProtocolRenderer.vue';
|
|
24
|
+
import type { WorkbenchEchartClickParams } from './chart/useEchart';
|
|
25
|
+
import type { WorkbenchRendererHostBridge } from './hostBridge';
|
|
26
|
+
import type {
|
|
27
|
+
CalendarCardData,
|
|
28
|
+
CategoryRankingData,
|
|
29
|
+
CustomCanvasData,
|
|
30
|
+
DashboardGridData,
|
|
31
|
+
DisplayBlockData,
|
|
32
|
+
EmbeddedFrameData,
|
|
33
|
+
FdeCustomComponentData,
|
|
34
|
+
GeoGlobeData,
|
|
35
|
+
InsightNarrativeData,
|
|
36
|
+
MaterializedBlock,
|
|
37
|
+
MetricSummaryData,
|
|
38
|
+
ProtocolRenderData,
|
|
39
|
+
ReportSummaryDisplayData,
|
|
40
|
+
RoleId,
|
|
41
|
+
TableRowsData,
|
|
42
|
+
TaskSummaryData,
|
|
43
|
+
WeatherCurrentData,
|
|
44
|
+
} from '../types';
|
|
45
|
+
|
|
46
|
+
import { useWorkbenchBlockRendererBindings } from './useWorkbenchBlockRendererBindings';
|
|
47
|
+
|
|
48
|
+
const props = withDefaults(defineProps<{
|
|
49
|
+
block: MaterializedBlock;
|
|
50
|
+
roleId?: RoleId | string;
|
|
51
|
+
userId?: string;
|
|
52
|
+
density?: 'thumbnail' | 'compact' | 'standard' | 'expanded';
|
|
53
|
+
hostBridge?: WorkbenchRendererHostBridge;
|
|
54
|
+
}>(), {
|
|
55
|
+
density: 'expanded',
|
|
56
|
+
hostBridge: undefined,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const emit = defineEmits<{
|
|
60
|
+
submitForm: [blockId: string, values: Record<string, unknown>];
|
|
61
|
+
submitSurvey: [blockId: string, answers: Record<string, unknown>];
|
|
62
|
+
executeAction: [blockId: string, actionId: string, actionLabel: string];
|
|
63
|
+
generateReport: [blockId: string];
|
|
64
|
+
workbenchShowcaseTabChange: [tabId: string];
|
|
65
|
+
runWorkbenchShortcut: [prompt: string];
|
|
66
|
+
replaceManualPlaceholder: [payload: { block: MaterializedBlock; overrideCapabilityId?: string }];
|
|
67
|
+
focusBlock: [blockId: string];
|
|
68
|
+
focusNestedBlock: [payload: { parentId: string; childId: string }];
|
|
69
|
+
chartClick: [payload: WorkbenchEchartClickParams & { blockId: string; block: MaterializedBlock }];
|
|
70
|
+
}>();
|
|
71
|
+
|
|
72
|
+
const {
|
|
73
|
+
chartRefreshRuntime,
|
|
74
|
+
effectiveBlock,
|
|
75
|
+
effectiveData,
|
|
76
|
+
formatMetricValue,
|
|
77
|
+
isFormBlockData,
|
|
78
|
+
isSurveyBlockData,
|
|
79
|
+
isActionGroupData,
|
|
80
|
+
isWorkflowBlockData,
|
|
81
|
+
isReportBlockData,
|
|
82
|
+
textValue,
|
|
83
|
+
numberValue,
|
|
84
|
+
welcomeBannerMetrics,
|
|
85
|
+
formValues,
|
|
86
|
+
surveyAnswers,
|
|
87
|
+
compactLimit,
|
|
88
|
+
toggleMultiValue,
|
|
89
|
+
formCompletedCount,
|
|
90
|
+
renderFieldType,
|
|
91
|
+
updateMatrixAnswer,
|
|
92
|
+
matrixAnswerValue,
|
|
93
|
+
multipleAnswerIncludes,
|
|
94
|
+
taskStatusClass,
|
|
95
|
+
taskTypeLabel,
|
|
96
|
+
taskStatusLabel,
|
|
97
|
+
tableRowsPreviewVisualKind,
|
|
98
|
+
tableRowsPreviewCard,
|
|
99
|
+
tableRowsPreviewRecords,
|
|
100
|
+
tableRowsPreviewCell,
|
|
101
|
+
tableRowsTimelinePrimaryCell,
|
|
102
|
+
tableRowsTimelineBadgeCell,
|
|
103
|
+
tableRowsPreviewAntTableColumns,
|
|
104
|
+
tableRowsPreviewAntTableRows,
|
|
105
|
+
tableRowsFallbackAntTableColumns,
|
|
106
|
+
tableRowsFallbackAntTableRows,
|
|
107
|
+
tableRowsAntTableScroll,
|
|
108
|
+
handleTableRowsAntTableColumnResize,
|
|
109
|
+
formatWeatherTemp,
|
|
110
|
+
weatherIcon,
|
|
111
|
+
isChartShape,
|
|
112
|
+
imageComposeEmptyChartPreview,
|
|
113
|
+
imageComposeChartPreview,
|
|
114
|
+
imageComposeMetricLeadingVisualKind,
|
|
115
|
+
imageComposeChartPreviewKind,
|
|
116
|
+
imageComposeChartPreviewMetric,
|
|
117
|
+
imageComposeChartPreviewStatus,
|
|
118
|
+
imageComposeChartPreviewBars,
|
|
119
|
+
imageComposeChartPreviewDonutStyle,
|
|
120
|
+
imageComposeEmptyRankingPreview,
|
|
121
|
+
imageComposeRankingPreviewItems,
|
|
122
|
+
imageComposeRankingPreviewLabel,
|
|
123
|
+
imageComposeRankingPreviewDetail,
|
|
124
|
+
imageComposeRankingPreviewValue,
|
|
125
|
+
imageComposeRankingPreviewAvatar,
|
|
126
|
+
imageComposeRankingPreviewAvatarClass,
|
|
127
|
+
imageComposeRankingPreviewValueClass,
|
|
128
|
+
imageComposeBidRowsCard,
|
|
129
|
+
imageComposeBidRowsVisualKind,
|
|
130
|
+
imageComposeBidInfoItems,
|
|
131
|
+
imageComposeBidRowsRecords,
|
|
132
|
+
imageComposeBidRowsColumns,
|
|
133
|
+
imageComposeBidRowsGridStyle,
|
|
134
|
+
imageComposeBidRowsCell,
|
|
135
|
+
imageComposeBidRowCards,
|
|
136
|
+
imageComposeBidPanelClasses,
|
|
137
|
+
imageComposeBidPillClasses,
|
|
138
|
+
imageComposeBidCardGridStyle,
|
|
139
|
+
imageComposeBidCardTileClasses,
|
|
140
|
+
imageComposeBidCardPillPlacementClasses,
|
|
141
|
+
imageComposeBidTargetInfoGridStyle,
|
|
142
|
+
imageComposeBidInfoTilePlacementStyle,
|
|
143
|
+
imageComposeBidInfoTileClasses,
|
|
144
|
+
imageComposeBidInfoLabelClasses,
|
|
145
|
+
imageComposeBidInfoValueClasses,
|
|
146
|
+
imageComposeBidConclusionCard,
|
|
147
|
+
imageComposeBidConclusionBadge,
|
|
148
|
+
imageComposeBidConclusionDetail,
|
|
149
|
+
activeTabFor,
|
|
150
|
+
tabsFor,
|
|
151
|
+
orgMetricValues,
|
|
152
|
+
visualFor,
|
|
153
|
+
rowGrid,
|
|
154
|
+
metricSummaryDisplayValue,
|
|
155
|
+
metricSummaryUnitLabel,
|
|
156
|
+
imageComposeMetricSubText,
|
|
157
|
+
imageComposeMetricFooterStatus,
|
|
158
|
+
imageComposeMetricFooterMain,
|
|
159
|
+
imageComposeMetricFooterStatusClass,
|
|
160
|
+
imageComposeMetricFooterVisible,
|
|
161
|
+
chartRendererKey,
|
|
162
|
+
manualReplacementView,
|
|
163
|
+
manualReplacementCapabilityOptionsForBlock,
|
|
164
|
+
manualReplacementCapabilityDraft,
|
|
165
|
+
setManualReplacementCapabilityDraft,
|
|
166
|
+
replaceManualPlaceholder,
|
|
167
|
+
nestedBlockDataSummary,
|
|
168
|
+
nestedBlockRendererKey,
|
|
169
|
+
nestedBlockComposeSource,
|
|
170
|
+
customCanvasVisibleNestedBlocks,
|
|
171
|
+
customCanvasUsesAbsoluteNestedBlocks,
|
|
172
|
+
customCanvasNestedBlockContainerClasses,
|
|
173
|
+
customCanvasDenseNestedStack,
|
|
174
|
+
customCanvasUsesNaturalNestedGrid,
|
|
175
|
+
customCanvasShouldFillNaturalNestedGrid,
|
|
176
|
+
customCanvasUsesReferenceCompositePreview,
|
|
177
|
+
customCanvasReferenceCompositeKind,
|
|
178
|
+
referenceCompositeHeaderChip,
|
|
179
|
+
customCanvasPageHeaderBlock,
|
|
180
|
+
customCanvasEmptyPageHeaderPlaceholder,
|
|
181
|
+
customCanvasEmptyImagePlaceholder,
|
|
182
|
+
customCanvasAlertLeafContainer,
|
|
183
|
+
customCanvasAlertLeafItems,
|
|
184
|
+
customCanvasHeaderTitle,
|
|
185
|
+
customCanvasHeaderSubtitle,
|
|
186
|
+
customCanvasHeaderLogo,
|
|
187
|
+
customCanvasHeaderLogoStyle,
|
|
188
|
+
customCanvasPageHeaderStyle,
|
|
189
|
+
customCanvasPageHeaderTextClass,
|
|
190
|
+
customCanvasHeaderPillsWithFallback,
|
|
191
|
+
referenceCompositeDiagnosticStyle,
|
|
192
|
+
referenceRiskMetricValue,
|
|
193
|
+
referenceRiskKpiItems,
|
|
194
|
+
referenceRiskMovementItems,
|
|
195
|
+
referenceOpsServiceItems,
|
|
196
|
+
referenceOpsResourceItems,
|
|
197
|
+
referenceOpsIncidentItems,
|
|
198
|
+
referenceSecurityScoreBlock,
|
|
199
|
+
referenceSecurityRiskItems,
|
|
200
|
+
referenceSecurityComplianceItems,
|
|
201
|
+
referenceAssetLedgerItems,
|
|
202
|
+
referenceAssetExceptionItems,
|
|
203
|
+
referenceCostItems,
|
|
204
|
+
referenceCostDonutItems,
|
|
205
|
+
referenceCostDonutStyle,
|
|
206
|
+
referenceProjectProgressItems,
|
|
207
|
+
referenceTodoItems,
|
|
208
|
+
referenceEfficiencyItems,
|
|
209
|
+
referenceQuickLinkItems,
|
|
210
|
+
referenceBusinessMetricItems,
|
|
211
|
+
referenceBusinessChartItems,
|
|
212
|
+
referenceBusinessListItems,
|
|
213
|
+
referenceBidHero,
|
|
214
|
+
referenceBidQuickActions,
|
|
215
|
+
referenceBidKpiItems,
|
|
216
|
+
referenceBidInfoItems,
|
|
217
|
+
referenceBidTableBlocks,
|
|
218
|
+
referenceBidRiskRows,
|
|
219
|
+
referenceBidConclusionItems,
|
|
220
|
+
referenceBidDataBoundaryItems,
|
|
221
|
+
referenceBidSanitizedMetricValue,
|
|
222
|
+
referenceNoticeItems,
|
|
223
|
+
referenceHealthRadarRiskItems,
|
|
224
|
+
referenceHealthRadarPoints,
|
|
225
|
+
referenceDeviationBars,
|
|
226
|
+
referenceDeviationRiskItems,
|
|
227
|
+
referenceFinanceRiskBottomItems,
|
|
228
|
+
referenceFinanceRiskMetricDisplayValue,
|
|
229
|
+
referenceHrOrganizationMetrics,
|
|
230
|
+
referenceHrOrganizationRows,
|
|
231
|
+
referenceHrRiskRows,
|
|
232
|
+
referenceHrPeopleCostItems,
|
|
233
|
+
referenceHrCostTrendItems,
|
|
234
|
+
referenceHrTalentMetrics,
|
|
235
|
+
referenceHrTalentTodoRows,
|
|
236
|
+
referenceExpenseRiskRows,
|
|
237
|
+
referenceExpenseSummaryItems,
|
|
238
|
+
referenceDeviationInsightItems,
|
|
239
|
+
referenceOrganizationRiskMetrics,
|
|
240
|
+
referenceOrganizationDonutStyle,
|
|
241
|
+
referenceInvestmentRiskRows,
|
|
242
|
+
referenceInvestmentSummaryItems,
|
|
243
|
+
referenceExecutiveTodoItems,
|
|
244
|
+
referenceExecutiveTodoBadge,
|
|
245
|
+
referenceExecutiveTodoBadgeClasses,
|
|
246
|
+
referenceExecutiveTodoImpact,
|
|
247
|
+
referenceExecutiveTodoDeadline,
|
|
248
|
+
referenceExecutiveTodoProgress,
|
|
249
|
+
referenceShortcutDrillItems,
|
|
250
|
+
referenceQuickWorkbenchGroups,
|
|
251
|
+
referenceQuickWorkbenchGroupItems,
|
|
252
|
+
referenceQuickWorkbenchUrgentBadge,
|
|
253
|
+
referenceStrategyKpiMetrics,
|
|
254
|
+
referenceOperationEfficiencyGroups,
|
|
255
|
+
referenceOperationEfficiencyPanelStyle,
|
|
256
|
+
referenceOperationHealthProgressItems,
|
|
257
|
+
referenceOperationHealthTrendItems,
|
|
258
|
+
referenceOperationHealthStructureBlock,
|
|
259
|
+
referenceOperationHealthStructureItems,
|
|
260
|
+
referenceStrategyKpiTrendPath,
|
|
261
|
+
referenceStrategyKpiRiskItems,
|
|
262
|
+
referenceStrategyKpiRiskSummaryLabel,
|
|
263
|
+
referenceStrategyKpiRiskItemsGridStyle,
|
|
264
|
+
referenceItemNestedCardAttrs,
|
|
265
|
+
referenceItemNestedRoleLabel,
|
|
266
|
+
focusReferenceNestedItem,
|
|
267
|
+
customCanvasNestedStackContainerStyle,
|
|
268
|
+
nestedBlockCanvasStyle,
|
|
269
|
+
nestedBlockStackTailPlacementStyle,
|
|
270
|
+
nestedBlockGridPlacementStyle,
|
|
271
|
+
nestedBlockAccentStyle,
|
|
272
|
+
customCanvasElementStyle,
|
|
273
|
+
customCanvasElementClasses,
|
|
274
|
+
customCanvasStyle,
|
|
275
|
+
customCanvasShellClasses,
|
|
276
|
+
nestedBlockShellClasses,
|
|
277
|
+
manualReplacementContainerStyle,
|
|
278
|
+
manualReplacementShellClasses,
|
|
279
|
+
manualReplacementCompactView,
|
|
280
|
+
manualReplacementCapabilityDraftLabel,
|
|
281
|
+
manualReplacementActionLabel,
|
|
282
|
+
manualReplacementPrimaryActionLabel,
|
|
283
|
+
dataBindingFailureReason,
|
|
284
|
+
dataBindingFailureQueryIntent,
|
|
285
|
+
dataBindingNeedsHumanIntervention,
|
|
286
|
+
nestedBlockNeedsHumanIntervention,
|
|
287
|
+
nestedBlockDataSnapshotRenderable,
|
|
288
|
+
imageComposeCompactCard,
|
|
289
|
+
imageComposeBusinessGapBadgeLabel,
|
|
290
|
+
customCanvasShowsStructureLabels,
|
|
291
|
+
customCanvasVisibleElements,
|
|
292
|
+
customCanvasOverlaysVisibleElements,
|
|
293
|
+
customCanvasVisibleNarrative,
|
|
294
|
+
customCanvasStandaloneQuickLinks,
|
|
295
|
+
customCanvasStandaloneQuickLinkItems,
|
|
296
|
+
dataBindingFailureRegistryLabel,
|
|
297
|
+
dataBindingFailureView,
|
|
298
|
+
metricSummaryShowsPrimaryLabel,
|
|
299
|
+
metricSummaryValueClass,
|
|
300
|
+
businessMetricMatrixLargePanel,
|
|
301
|
+
imageComposeMetricSummaryCardClasses,
|
|
302
|
+
imageComposeMetricSummaryCardStyle,
|
|
303
|
+
imageComposeMetricTitleClass,
|
|
304
|
+
imageComposeMetricValueRowClass,
|
|
305
|
+
imageComposeMetricValueClass,
|
|
306
|
+
imageComposeMetricValueStyle,
|
|
307
|
+
imageComposeMetricUnitClass,
|
|
308
|
+
metricSummaryShowsChrome,
|
|
309
|
+
metricSummaryShowsComparisonBadge,
|
|
310
|
+
imageComposeAlertRankingCard,
|
|
311
|
+
imageComposeAlertRankingItems,
|
|
312
|
+
imageComposeAlertRankingSeverity,
|
|
313
|
+
imageComposeAlertRankingTitle,
|
|
314
|
+
imageComposeAlertRankingTime,
|
|
315
|
+
imageComposeAlertSeverityClasses,
|
|
316
|
+
nestedBlockMetricValue,
|
|
317
|
+
nestedBlockVisualKind,
|
|
318
|
+
nestedBlockItems,
|
|
319
|
+
nestedBlockBarItems,
|
|
320
|
+
nestedBlockTileItems,
|
|
321
|
+
nestedBlockItemLabel,
|
|
322
|
+
nestedBlockItemValue,
|
|
323
|
+
nestedBlockItemDetail,
|
|
324
|
+
nestedBlockItemTitle,
|
|
325
|
+
nestedBlockItemSeverity,
|
|
326
|
+
nestedBlockItemTime,
|
|
327
|
+
nestedBlockPercent,
|
|
328
|
+
nestedBlockItemProgress,
|
|
329
|
+
referenceOpsTrendChartItems,
|
|
330
|
+
nestedBlockToneClass,
|
|
331
|
+
nestedBlockStatusSummary,
|
|
332
|
+
nestedBlockStatusSummaryLabel,
|
|
333
|
+
nestedBlockPillClasses,
|
|
334
|
+
nestedBlockDotClasses,
|
|
335
|
+
nestedBlockBarClasses,
|
|
336
|
+
referenceOpsTrendBarClasses,
|
|
337
|
+
nestedBlockBarStyle,
|
|
338
|
+
nestedBlockProgressStage,
|
|
339
|
+
nestedBlockSecurityScore,
|
|
340
|
+
nestedBlockSecurityScoreRingLabel,
|
|
341
|
+
nestedBlockSecurityMetrics,
|
|
342
|
+
nestedBlockDonutItems,
|
|
343
|
+
nestedBlockDonutStyle,
|
|
344
|
+
nestedBlockQuickIconLabel,
|
|
345
|
+
nestedBlockQuickLinksGridStyle,
|
|
346
|
+
nestedBlockRows,
|
|
347
|
+
nestedBlockColumns,
|
|
348
|
+
nestedBlockRankingItems,
|
|
349
|
+
nestedBlockCell,
|
|
350
|
+
nestedBlockCompactPreview,
|
|
351
|
+
nestedBlockEmptyImageContainer,
|
|
352
|
+
nestedBlockFailureReason,
|
|
353
|
+
nestedBlockBusinessGapReason,
|
|
354
|
+
nestedBlockQueryIntent,
|
|
355
|
+
nestedBlockFocusTitle,
|
|
356
|
+
focusNestedBlock,
|
|
357
|
+
fdeCustomComponentRenderState,
|
|
358
|
+
} = useWorkbenchBlockRendererBindings(props, emit as unknown as (event: string, ...args: unknown[]) => void);
|
|
359
|
+
</script>
|
|
360
|
+
|
|
361
|
+
<template>
|
|
362
|
+
<div
|
|
363
|
+
class="h-full min-h-0 w-full"
|
|
364
|
+
:data-image-compose-business-gap-label="imageComposeCompactCard(effectiveBlock) ? imageComposeBusinessGapBadgeLabel(effectiveBlock) : undefined"
|
|
365
|
+
>
|
|
366
|
+
<template v-if="effectiveBlock.blockType === 'display'">
|
|
367
|
+
<template v-if="effectiveBlock.meta?.fullValidationRole === 'group'">
|
|
368
|
+
<div class="flex h-full min-h-0 items-center rounded-lg border border-blue-100 bg-white p-[5px] shadow-sm">
|
|
369
|
+
<div class="flex min-h-0 w-full items-center gap-2 overflow-hidden">
|
|
370
|
+
<button
|
|
371
|
+
v-for="tab in tabsFor(effectiveBlock)"
|
|
372
|
+
:key="textValue(tab.id)"
|
|
373
|
+
type="button"
|
|
374
|
+
:class="[
|
|
375
|
+
'workbench-card-action flex min-w-0 shrink-0 items-center justify-center rounded-full border px-4 py-1.5 text-xs font-semibold leading-none transition',
|
|
376
|
+
textValue(tab.id) === textValue(activeTabFor(effectiveBlock).id, 'all-capabilities')
|
|
377
|
+
? 'border-[#4f73ff] bg-[#4f73ff] text-white shadow-sm'
|
|
378
|
+
: 'border-transparent bg-[#edf4ff] text-[#4f73ff] hover:bg-[#e3edff]',
|
|
379
|
+
]"
|
|
380
|
+
@click="textValue(tab.id) && emit('workbenchShowcaseTabChange', textValue(tab.id))"
|
|
381
|
+
>
|
|
382
|
+
<span class="min-w-0 truncate">{{ textValue(tab.shortName, textValue(tab.name, textValue(tab.id))) }}</span>
|
|
383
|
+
</button>
|
|
384
|
+
</div>
|
|
385
|
+
</div>
|
|
386
|
+
</template>
|
|
387
|
+
|
|
388
|
+
<template v-else-if="effectiveBlock.meta?.organizationKind === 'welcome_banner' || effectiveBlock.meta?.fullValidationRole === 'banner'">
|
|
389
|
+
<component
|
|
390
|
+
:is="hostBridge?.WelcomeBanner"
|
|
391
|
+
v-if="hostBridge?.WelcomeBanner"
|
|
392
|
+
:portal-metrics="welcomeBannerMetrics(effectiveBlock)"
|
|
393
|
+
class="h-full min-h-0"
|
|
394
|
+
/>
|
|
395
|
+
<div v-else class="flex h-full min-h-0 flex-col justify-center rounded-lg border border-blue-100 bg-blue-50 px-4 py-3 text-blue-900">
|
|
396
|
+
<div class="text-xs text-blue-500">欢迎回来 / 百特搭工作台</div>
|
|
397
|
+
<div class="mt-1 text-lg font-semibold">{{ effectiveBlock.title }}</div>
|
|
398
|
+
</div>
|
|
399
|
+
</template>
|
|
400
|
+
|
|
401
|
+
<template v-else-if="dataBindingFailureView(effectiveBlock)">
|
|
402
|
+
<div class="workbench-data-binding-failure-placeholder grid h-full min-h-0 w-full grid-rows-[auto_minmax(0,1fr)_auto] overflow-hidden rounded-lg border border-rose-100 bg-rose-50 px-3 py-2 text-rose-900">
|
|
403
|
+
<div class="min-w-0">
|
|
404
|
+
<div class="inline-flex max-w-full rounded-full bg-white px-2 py-0.5 text-xs font-semibold leading-5 text-rose-700">
|
|
405
|
+
{{ dataBindingNeedsHumanIntervention(effectiveBlock) ? '需补充业务口径' : '问数失败' }}
|
|
406
|
+
</div>
|
|
407
|
+
<div class="mt-1 truncate text-xs font-semibold leading-4 text-slate-950" :title="effectiveBlock.title || dataBindingFailureRegistryLabel(effectiveBlock)">
|
|
408
|
+
{{ effectiveBlock.title || dataBindingFailureRegistryLabel(effectiveBlock) }}
|
|
409
|
+
</div>
|
|
410
|
+
</div>
|
|
411
|
+
<p class="min-h-0 overflow-hidden text-xs leading-4 text-rose-800" :title="dataBindingFailureReason(effectiveBlock)">
|
|
412
|
+
{{ dataBindingFailureReason(effectiveBlock) }}
|
|
413
|
+
</p>
|
|
414
|
+
<div class="min-w-0 text-xs leading-4 text-slate-600">
|
|
415
|
+
<span class="min-w-0 truncate" :title="dataBindingFailureQueryIntent(effectiveBlock)">{{ dataBindingFailureQueryIntent(effectiveBlock) }}</span>
|
|
416
|
+
</div>
|
|
417
|
+
</div>
|
|
418
|
+
</template>
|
|
419
|
+
|
|
420
|
+
<template v-else-if="effectiveBlock.meta?.workbenchOrganizationCard === true || textValue(effectiveBlock.meta?.macroCapabilityId) === 'card.workbench_organization' || String(effectiveBlock.id).startsWith('workbench-org-')">
|
|
421
|
+
<div v-if="effectiveBlock.meta?.organizationKind === 'capability_overview'" class="grid h-full content-start gap-2 sm:grid-cols-2">
|
|
422
|
+
<div v-for="item in orgMetricValues(effectiveBlock)" :key="item.label" class="rounded-md border border-blue-100 bg-white px-2.5 py-2">
|
|
423
|
+
<div class="flex items-center gap-1.5 text-[11px] text-slate-500">
|
|
424
|
+
<component :is="item.icon" class="h-3.5 w-3.5 text-blue-600" />
|
|
425
|
+
{{ item.label }}
|
|
426
|
+
</div>
|
|
427
|
+
<div class="mt-1 text-lg font-semibold leading-none text-slate-950">{{ item.value }}</div>
|
|
428
|
+
</div>
|
|
429
|
+
</div>
|
|
430
|
+
<div v-else-if="effectiveBlock.meta?.organizationKind === 'ai_shortcut'" class="grid gap-2">
|
|
431
|
+
<button
|
|
432
|
+
v-for="shortcut in ['只看图表卡能力', '把全部验收卡按分类说明一下', '生成 CEO 角色首页推荐布局', '检查当前画布哪些卡片适合改成大屏']"
|
|
433
|
+
:key="shortcut"
|
|
434
|
+
type="button"
|
|
435
|
+
class="workbench-card-action h-8 rounded-md border border-slate-200 bg-slate-50 px-2 text-left text-[11px] font-medium text-slate-700 transition hover:border-blue-200 hover:bg-blue-50 hover:text-blue-700"
|
|
436
|
+
@click="emit('runWorkbenchShortcut', shortcut)"
|
|
437
|
+
>
|
|
438
|
+
{{ shortcut }}
|
|
439
|
+
</button>
|
|
440
|
+
</div>
|
|
441
|
+
<div v-else-if="effectiveBlock.meta?.organizationKind === 'category_navigator'" class="flex h-full min-h-0 items-center">
|
|
442
|
+
<div class="flex w-full max-h-full flex-wrap items-center gap-1.5 overflow-y-auto pr-1">
|
|
443
|
+
<button
|
|
444
|
+
v-for="tab in tabsFor(effectiveBlock)"
|
|
445
|
+
:key="textValue(tab.id)"
|
|
446
|
+
type="button"
|
|
447
|
+
:class="[
|
|
448
|
+
'workbench-card-action h-6 shrink-0 whitespace-nowrap rounded-full border px-2 text-[11px] font-semibold leading-none transition',
|
|
449
|
+
textValue(tab.id) === textValue(activeTabFor(effectiveBlock).id, 'all-capabilities')
|
|
450
|
+
? 'border-blue-600 bg-blue-600 text-white shadow-sm'
|
|
451
|
+
: 'border-slate-200 bg-white text-slate-600 hover:border-blue-200 hover:bg-blue-50 hover:text-blue-700',
|
|
452
|
+
]"
|
|
453
|
+
@click="textValue(tab.id) && emit('workbenchShowcaseTabChange', textValue(tab.id))"
|
|
454
|
+
>
|
|
455
|
+
{{ textValue(tab.shortName, textValue(tab.name, textValue(tab.id))) }}
|
|
456
|
+
<span :class="textValue(tab.id) === textValue(activeTabFor(effectiveBlock).id, 'all-capabilities') ? 'ml-1 text-xs text-blue-100' : 'ml-1 text-xs text-slate-400'">
|
|
457
|
+
{{ numberValue(tab.count) }}
|
|
458
|
+
</span>
|
|
459
|
+
</button>
|
|
460
|
+
</div>
|
|
461
|
+
</div>
|
|
462
|
+
<div v-else-if="effectiveBlock.meta?.organizationKind === 'section_description'" class="rounded-lg border border-slate-200 bg-slate-50 px-3 py-2">
|
|
463
|
+
<div class="flex flex-wrap items-center gap-2">
|
|
464
|
+
<span class="rounded-full border border-blue-200 bg-white px-2 py-0.5 text-[11px] font-semibold text-blue-700">
|
|
465
|
+
{{ textValue(activeTabFor(effectiveBlock).shortName, '全部') }} · {{ numberValue(activeTabFor(effectiveBlock).count) }} 个能力
|
|
466
|
+
</span>
|
|
467
|
+
<span class="text-[11px] text-slate-500">{{ textValue(activeTabFor(effectiveBlock).id, 'all-capabilities') === 'all-capabilities' ? '当前可配置完整画布。' : '当前分类排版会同步到全部视图。' }}</span>
|
|
468
|
+
</div>
|
|
469
|
+
<p class="mt-1 text-xs leading-5 text-slate-600">{{ textValue(activeTabFor(effectiveBlock).description, '展示当前能力分类的业务场景和使用边界。') }}</p>
|
|
470
|
+
</div>
|
|
471
|
+
</template>
|
|
472
|
+
|
|
473
|
+
<template v-else-if="effectiveData?.shape === 'metricSummary'">
|
|
474
|
+
<div
|
|
475
|
+
v-if="imageComposeCompactCard(effectiveBlock)"
|
|
476
|
+
class="workbench-image-metric-summary-card grid h-full min-h-0 w-full grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-lg bg-white"
|
|
477
|
+
:class="imageComposeMetricSummaryCardClasses(effectiveBlock)"
|
|
478
|
+
:style="imageComposeMetricSummaryCardStyle()"
|
|
479
|
+
>
|
|
480
|
+
<div class="grid min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-2">
|
|
481
|
+
<div :class="['truncate font-semibold text-slate-600', imageComposeMetricTitleClass(effectiveBlock)]" :title="effectiveBlock.title">{{ effectiveBlock.title }}</div>
|
|
482
|
+
<span v-if="imageComposeMetricLeadingVisualKind(effectiveBlock) === 'bars'" class="flex shrink-0 items-end gap-0.5 opacity-80" aria-hidden="true">
|
|
483
|
+
<i class="h-2 w-1 rounded-full bg-[#4c2cff]" />
|
|
484
|
+
<i class="h-3 w-1 rounded-full bg-[#4c2cff]/70" />
|
|
485
|
+
<i class="h-4 w-1 rounded-full bg-[#4c2cff]" />
|
|
486
|
+
</span>
|
|
487
|
+
<svg v-else-if="imageComposeMetricLeadingVisualKind(effectiveBlock) === 'sparkline'" class="h-5 w-12 shrink-0" viewBox="0 0 48 20" preserveAspectRatio="none" aria-hidden="true">
|
|
488
|
+
<path d="M1 15 C8 11, 12 16, 18 10 S29 4, 36 8 S43 11, 47 5" fill="none" stroke="#4c2cff" stroke-width="2.5" stroke-linecap="round" />
|
|
489
|
+
<path d="M1 17 C9 14, 15 18, 22 13 S33 8, 47 10" fill="none" stroke="#19c7ad" stroke-width="1.5" stroke-linecap="round" opacity="0.72" />
|
|
490
|
+
</svg>
|
|
491
|
+
<span v-else class="grid h-8 w-8 shrink-0 place-items-center rounded-full bg-[#f0efff] text-xs font-semibold text-[#4c2cff]" aria-hidden="true">
|
|
492
|
+
{{ textValue(effectiveBlock.title, 'K').slice(0, 1).toUpperCase() }}
|
|
493
|
+
</span>
|
|
494
|
+
</div>
|
|
495
|
+
<div :class="['flex min-h-0 min-w-0 flex-1 items-center', imageComposeMetricValueRowClass(effectiveBlock)]">
|
|
496
|
+
<div class="flex min-w-0 items-baseline gap-1">
|
|
497
|
+
<div
|
|
498
|
+
:class="['workbench-image-metric-value max-w-full whitespace-nowrap font-semibold leading-none text-slate-950', imageComposeMetricValueClass(effectiveBlock)]"
|
|
499
|
+
:style="imageComposeMetricValueStyle(effectiveBlock)"
|
|
500
|
+
:title="metricSummaryDisplayValue(effectiveData as MetricSummaryData & Record<string, unknown>)"
|
|
501
|
+
>
|
|
502
|
+
{{ metricSummaryDisplayValue(effectiveData as MetricSummaryData & Record<string, unknown>) }}
|
|
503
|
+
</div>
|
|
504
|
+
<span v-if="metricSummaryUnitLabel(effectiveData as MetricSummaryData & Record<string, unknown>)" :class="['shrink-0 font-semibold text-slate-500', imageComposeMetricUnitClass(effectiveBlock)]">
|
|
505
|
+
{{ metricSummaryUnitLabel(effectiveData as MetricSummaryData & Record<string, unknown>) }}
|
|
506
|
+
</span>
|
|
507
|
+
</div>
|
|
508
|
+
</div>
|
|
509
|
+
<div
|
|
510
|
+
v-if="imageComposeMetricFooterVisible(effectiveBlock, effectiveData as MetricSummaryData & Record<string, unknown>)"
|
|
511
|
+
class="grid min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-2 text-xs leading-5"
|
|
512
|
+
:title="imageComposeMetricSubText(effectiveData as MetricSummaryData & Record<string, unknown>)"
|
|
513
|
+
>
|
|
514
|
+
<span class="min-w-0 truncate text-slate-500">{{ imageComposeMetricFooterMain(effectiveData as MetricSummaryData & Record<string, unknown>) }}</span>
|
|
515
|
+
<span
|
|
516
|
+
v-if="imageComposeMetricFooterStatus(effectiveData as MetricSummaryData & Record<string, unknown>)"
|
|
517
|
+
:class="['max-w-[5.5rem] shrink-0 truncate text-right font-semibold', imageComposeMetricFooterStatusClass(imageComposeMetricFooterStatus(effectiveData as MetricSummaryData & Record<string, unknown>))]"
|
|
518
|
+
>
|
|
519
|
+
{{ imageComposeMetricFooterStatus(effectiveData as MetricSummaryData & Record<string, unknown>) }}
|
|
520
|
+
</span>
|
|
521
|
+
</div>
|
|
522
|
+
</div>
|
|
523
|
+
<div v-else-if="visualFor(effectiveBlock).metricVariant === 'centerNumber'" class="flex h-full min-h-0 w-full flex-col items-center justify-center text-center">
|
|
524
|
+
<div v-if="!visualFor(effectiveBlock).hideMetricLabel" class="mb-1 text-[11px] text-slate-400">{{ (effectiveData as MetricSummaryData).primaryLabel }}</div>
|
|
525
|
+
<div class="font-semibold leading-none text-slate-950" :class="density === 'thumbnail' ? 'text-3xl' : density === 'compact' ? 'text-4xl' : 'text-5xl'" :style="visualFor(effectiveBlock).accentColor ? { color: visualFor(effectiveBlock).accentColor } : undefined">
|
|
526
|
+
{{ metricSummaryDisplayValue(effectiveData as MetricSummaryData & Record<string, unknown>) }}
|
|
527
|
+
</div>
|
|
528
|
+
<div v-if="!visualFor(effectiveBlock).hideMetricFooter && density !== 'thumbnail'" class="mt-2 text-xs text-slate-500">{{ (effectiveData as MetricSummaryData).periodLabel }}</div>
|
|
529
|
+
</div>
|
|
530
|
+
<div v-else class="flex h-full min-h-0 w-full flex-col justify-between overflow-hidden space-y-5">
|
|
531
|
+
<div class="flex items-end justify-between gap-2">
|
|
532
|
+
<div class="min-w-0">
|
|
533
|
+
<div v-if="metricSummaryShowsPrimaryLabel(effectiveBlock, effectiveData as MetricSummaryData)" class="truncate text-[11px] text-slate-400">{{ (effectiveData as MetricSummaryData).primaryLabel }}</div>
|
|
534
|
+
<div class="font-semibold leading-none text-slate-950" :class="[metricSummaryValueClass(effectiveBlock), metricSummaryShowsPrimaryLabel(effectiveBlock, effectiveData as MetricSummaryData) ? 'mt-2' : 'mt-0']">
|
|
535
|
+
{{ metricSummaryDisplayValue(effectiveData as MetricSummaryData & Record<string, unknown>) }}
|
|
536
|
+
</div>
|
|
537
|
+
</div>
|
|
538
|
+
<div v-if="metricSummaryShowsComparisonBadge(effectiveBlock, effectiveData as MetricSummaryData)" :class="['rounded-full px-3 py-1 text-xs font-semibold', ((effectiveData as MetricSummaryData).deltaPct || 0) >= 0 ? 'bg-emerald-50 text-emerald-600' : 'bg-rose-50 text-rose-600']">
|
|
539
|
+
{{ `${(effectiveData as MetricSummaryData).compareLabel} ${(((effectiveData as MetricSummaryData).deltaPct || 0) * 100).toFixed(1)}%` }}
|
|
540
|
+
</div>
|
|
541
|
+
</div>
|
|
542
|
+
<div v-if="metricSummaryShowsChrome(effectiveBlock, effectiveData as MetricSummaryData) && !visualFor(effectiveBlock).hideSecondary" class="grid gap-3 sm:grid-cols-2">
|
|
543
|
+
<div v-for="item in compactLimit((effectiveData as MetricSummaryData).secondary, 0, 1)" :key="item.label" class="rounded-lg border border-slate-100 bg-slate-50/80 p-3">
|
|
544
|
+
<div class="text-xs text-slate-500">{{ item.label }}</div>
|
|
545
|
+
<div class="mt-2 text-lg font-semibold text-slate-900">{{ formatMetricValue(item.value, item.format) }}</div>
|
|
546
|
+
</div>
|
|
547
|
+
</div>
|
|
548
|
+
<div v-if="metricSummaryShowsChrome(effectiveBlock, effectiveData as MetricSummaryData) && !visualFor(effectiveBlock).hideMetricFooter" class="flex items-center justify-between text-xs text-slate-500">
|
|
549
|
+
<span>{{ (effectiveData as MetricSummaryData).periodLabel }}</span>
|
|
550
|
+
<span>{{ (effectiveData as MetricSummaryData).sourceLabel }}</span>
|
|
551
|
+
</div>
|
|
552
|
+
</div>
|
|
553
|
+
</template>
|
|
554
|
+
|
|
555
|
+
<!-- 通用卡片协议分发 -->
|
|
556
|
+
<template v-else-if="effectiveData?.shape === 'protocolRender' && effectiveData?.rendererType === 'echarts'">
|
|
557
|
+
<EChartsProtocolRenderer
|
|
558
|
+
:configPayload="(effectiveData as ProtocolRenderData).protocolConfig"
|
|
559
|
+
:dataPayload="(effectiveData as ProtocolRenderData).protocolData"
|
|
560
|
+
:cardTitle="effectiveBlock.title"
|
|
561
|
+
:roleId="roleId"
|
|
562
|
+
:userId="userId"
|
|
563
|
+
:dataBinding="(effectiveData as ProtocolRenderData).dataBinding"
|
|
564
|
+
:blockMeta="effectiveBlock.meta"
|
|
565
|
+
:blockSource="effectiveBlock.source"
|
|
566
|
+
:refreshRuntime="chartRefreshRuntime"
|
|
567
|
+
@chart-click="emit('chartClick', { ...$event, blockId: effectiveBlock.id, block: effectiveBlock })"
|
|
568
|
+
/>
|
|
569
|
+
</template>
|
|
570
|
+
|
|
571
|
+
<template v-else-if="imageComposeChartPreview(effectiveBlock, effectiveData) || imageComposeEmptyChartPreview(effectiveBlock, effectiveData)">
|
|
572
|
+
<div class="workbench-image-empty-chart-preview flex h-full min-h-0 w-full flex-col overflow-hidden rounded-lg border border-slate-200 bg-white px-4 py-3 shadow-[0_2px_8px_rgba(15,23,42,0.04)]">
|
|
573
|
+
<div class="workbench-image-empty-chart-preview__header grid min-w-0 grid-cols-[minmax(0,1fr)_auto] items-start gap-3">
|
|
574
|
+
<div class="min-w-0">
|
|
575
|
+
<div class="truncate text-[11px] font-semibold leading-4 text-slate-400" :title="effectiveBlock.title">{{ effectiveBlock.title }}</div>
|
|
576
|
+
<div class="mt-1 truncate text-xl font-semibold leading-6 text-slate-950" :title="imageComposeChartPreviewMetric(effectiveBlock, effectiveData)">
|
|
577
|
+
{{ imageComposeChartPreviewMetric(effectiveBlock, effectiveData) }}
|
|
578
|
+
</div>
|
|
579
|
+
<div v-if="imageComposeChartPreviewStatus(effectiveBlock, effectiveData)" class="mt-1 inline-flex max-w-full items-center gap-1 rounded bg-[#e8fbf7] px-1.5 py-0.5 text-[11px] font-semibold leading-4 text-[#0f9f8b]">
|
|
580
|
+
<span class="h-1.5 w-1.5 rounded-full bg-[#19c7ad]" aria-hidden="true" />
|
|
581
|
+
<span class="min-w-0 truncate">{{ imageComposeChartPreviewStatus(effectiveBlock, effectiveData) }}</span>
|
|
582
|
+
</div>
|
|
583
|
+
</div>
|
|
584
|
+
<span class="flex shrink-0 items-end gap-0.5 pt-1 opacity-80" aria-hidden="true">
|
|
585
|
+
<i class="h-2 w-1 rounded-full bg-[#4c2cff]" />
|
|
586
|
+
<i class="h-3 w-1 rounded-full bg-[#4c2cff]/70" />
|
|
587
|
+
<i class="h-4 w-1 rounded-full bg-[#4c2cff]" />
|
|
588
|
+
</span>
|
|
589
|
+
</div>
|
|
590
|
+
<div class="workbench-image-empty-chart-preview__plot workbench-image-empty-chart-preview__plot-frame relative mt-3 min-h-0 flex-1 overflow-hidden rounded-md border border-slate-100 bg-slate-50/70 px-2 py-2">
|
|
591
|
+
<div class="workbench-image-empty-chart-preview__plot-grid pointer-events-none absolute inset-x-2 bottom-8 top-3 grid grid-rows-4" aria-hidden="true">
|
|
592
|
+
<span class="border-t border-slate-200/90" />
|
|
593
|
+
<span class="border-t border-slate-200/80" />
|
|
594
|
+
<span class="border-t border-slate-200/70" />
|
|
595
|
+
<span class="border-t border-slate-200/60" />
|
|
596
|
+
</div>
|
|
597
|
+
<div class="workbench-image-empty-chart-preview__plot-axis pointer-events-none absolute inset-x-2 bottom-8 h-px bg-slate-300" aria-hidden="true" />
|
|
598
|
+
<div
|
|
599
|
+
v-if="imageComposeChartPreviewKind(effectiveBlock, effectiveData) === 'donut'"
|
|
600
|
+
class="relative z-10 flex h-full min-h-0 items-center justify-center"
|
|
601
|
+
>
|
|
602
|
+
<span
|
|
603
|
+
class="block h-28 w-28 rounded-full"
|
|
604
|
+
:style="imageComposeChartPreviewDonutStyle(effectiveBlock, effectiveData)"
|
|
605
|
+
aria-hidden="true"
|
|
606
|
+
>
|
|
607
|
+
<span class="m-7 block h-14 w-14 rounded-full bg-white shadow-inner" />
|
|
608
|
+
</span>
|
|
609
|
+
</div>
|
|
610
|
+
<svg v-else class="relative z-10 h-full w-full" viewBox="0 0 360 128" preserveAspectRatio="none" aria-hidden="true">
|
|
611
|
+
<g opacity="0.72" stroke="#edf0f7" stroke-width="1">
|
|
612
|
+
<line x1="0" y1="28" x2="360" y2="28" />
|
|
613
|
+
<line x1="0" y1="64" x2="360" y2="64" />
|
|
614
|
+
<line x1="0" y1="100" x2="360" y2="100" />
|
|
615
|
+
</g>
|
|
616
|
+
<line x1="0" y1="36" x2="360" y2="36" stroke="#6d5cff" stroke-width="1.5" stroke-dasharray="6 8" opacity="0.28" />
|
|
617
|
+
<g
|
|
618
|
+
v-if="imageComposeChartPreviewKind(effectiveBlock, effectiveData) === 'bar' || imageComposeChartPreviewKind(effectiveBlock, effectiveData) === 'mixed'"
|
|
619
|
+
fill="#edeff6"
|
|
620
|
+
>
|
|
621
|
+
<rect
|
|
622
|
+
v-for="bar in imageComposeChartPreviewBars(effectiveBlock, effectiveData)"
|
|
623
|
+
:key="`${bar.x}-${bar.height}-${bar.label}`"
|
|
624
|
+
:x="bar.x"
|
|
625
|
+
:y="bar.y"
|
|
626
|
+
:width="bar.width"
|
|
627
|
+
:height="bar.height"
|
|
628
|
+
rx="5"
|
|
629
|
+
:fill="bar.fill"
|
|
630
|
+
:opacity="bar.opacity"
|
|
631
|
+
/>
|
|
632
|
+
</g>
|
|
633
|
+
<path
|
|
634
|
+
v-if="imageComposeChartPreviewKind(effectiveBlock, effectiveData) === 'line' || imageComposeChartPreviewKind(effectiveBlock, effectiveData) === 'mixed'"
|
|
635
|
+
d="M0 94 C42 96, 72 78, 104 82 C140 86, 154 48, 190 56 C222 62, 236 94, 270 84 C308 72, 328 46, 360 52"
|
|
636
|
+
fill="none"
|
|
637
|
+
stroke="#3426d9"
|
|
638
|
+
stroke-width="4"
|
|
639
|
+
stroke-linecap="round"
|
|
640
|
+
/>
|
|
641
|
+
<path
|
|
642
|
+
v-if="imageComposeChartPreviewKind(effectiveBlock, effectiveData) === 'line' || imageComposeChartPreviewKind(effectiveBlock, effectiveData) === 'mixed'"
|
|
643
|
+
d="M0 100 C48 92, 76 110, 118 96 C154 84, 186 92, 220 74 C256 54, 290 70, 322 58 C340 52, 350 52, 360 54"
|
|
644
|
+
fill="none"
|
|
645
|
+
stroke="#19c7ad"
|
|
646
|
+
stroke-width="2.5"
|
|
647
|
+
stroke-linecap="round"
|
|
648
|
+
opacity="0.55"
|
|
649
|
+
/>
|
|
650
|
+
</svg>
|
|
651
|
+
<div class="hidden">
|
|
652
|
+
<span class="truncate">基准线</span>
|
|
653
|
+
<span class="truncate text-center">异动区间</span>
|
|
654
|
+
<span class="truncate text-right">待回填</span>
|
|
655
|
+
</div>
|
|
656
|
+
</div>
|
|
657
|
+
</div>
|
|
658
|
+
</template>
|
|
659
|
+
|
|
660
|
+
<ChartRegistryRenderer
|
|
661
|
+
v-else-if="isChartShape(effectiveData) && !imageComposeCompactCard(effectiveBlock)"
|
|
662
|
+
:renderer-key="chartRendererKey(effectiveBlock)"
|
|
663
|
+
:data="effectiveData as DisplayBlockData"
|
|
664
|
+
:card-title="effectiveBlock.title"
|
|
665
|
+
:role-id="roleId"
|
|
666
|
+
:user-id="userId"
|
|
667
|
+
:density="density"
|
|
668
|
+
:block-meta="effectiveBlock.meta"
|
|
669
|
+
:block-source="effectiveBlock.source"
|
|
670
|
+
:refresh-runtime="chartRefreshRuntime"
|
|
671
|
+
@chart-click="emit('chartClick', { ...$event, blockId: effectiveBlock.id, block: effectiveBlock })"
|
|
672
|
+
/>
|
|
673
|
+
|
|
674
|
+
<div
|
|
675
|
+
v-else-if="isChartShape(effectiveData)"
|
|
676
|
+
class="workbench-image-system-chart-card grid h-full min-h-0 w-full grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-lg border border-slate-200 bg-white px-4 py-3 shadow-[0_2px_8px_rgba(15,23,42,0.04)]"
|
|
677
|
+
>
|
|
678
|
+
<div class="min-w-0">
|
|
679
|
+
<strong class="block truncate text-sm font-semibold leading-5 text-slate-900" :title="effectiveBlock.title">{{ effectiveBlock.title }}</strong>
|
|
680
|
+
<span v-if="effectiveBlock.subtitle" class="mt-0.5 block truncate text-xs leading-4 text-slate-500" :title="effectiveBlock.subtitle">{{ effectiveBlock.subtitle }}</span>
|
|
681
|
+
</div>
|
|
682
|
+
<ChartRegistryRenderer
|
|
683
|
+
class="min-h-0"
|
|
684
|
+
:renderer-key="chartRendererKey(effectiveBlock)"
|
|
685
|
+
:data="effectiveData as DisplayBlockData"
|
|
686
|
+
:card-title="effectiveBlock.title"
|
|
687
|
+
:role-id="roleId"
|
|
688
|
+
:user-id="userId"
|
|
689
|
+
:density="density"
|
|
690
|
+
:block-meta="effectiveBlock.meta"
|
|
691
|
+
:block-source="effectiveBlock.source"
|
|
692
|
+
:refresh-runtime="chartRefreshRuntime"
|
|
693
|
+
@chart-click="emit('chartClick', { ...$event, blockId: effectiveBlock.id, block: effectiveBlock })"
|
|
694
|
+
/>
|
|
695
|
+
</div>
|
|
696
|
+
|
|
697
|
+
<template v-else-if="effectiveData?.shape === 'categoryRanking'">
|
|
698
|
+
<div
|
|
699
|
+
v-if="imageComposeAlertRankingCard(effectiveBlock, effectiveData as CategoryRankingData)"
|
|
700
|
+
class="workbench-image-alert-ranking-list flex h-full min-h-0 w-full flex-col overflow-hidden rounded-md bg-[#241817] px-5 py-3 text-[#f8efe9]"
|
|
701
|
+
>
|
|
702
|
+
<div class="mb-1 flex h-6 shrink-0 items-center justify-between gap-2 pr-2">
|
|
703
|
+
<span class="min-w-0 truncate text-base font-semibold leading-5 text-[#fff7ed]" :title="effectiveBlock.title">{{ effectiveBlock.title }}</span>
|
|
704
|
+
<span class="rounded-full bg-red-600 px-2.5 py-1 text-xs font-semibold leading-none text-white">P1</span>
|
|
705
|
+
</div>
|
|
706
|
+
<div class="grid min-h-0 flex-1 gap-1 overflow-hidden" style="grid-template-rows: repeat(3, minmax(28px, 1fr));">
|
|
707
|
+
<div
|
|
708
|
+
v-for="(item, index) in imageComposeAlertRankingItems(effectiveBlock, effectiveData as CategoryRankingData).slice(0, 3)"
|
|
709
|
+
:key="`image-alert-${index}-${imageComposeAlertRankingTitle(item, index)}`"
|
|
710
|
+
class="workbench-image-alert-ranking-row grid min-h-0 items-center overflow-hidden rounded-md bg-transparent text-sm"
|
|
711
|
+
>
|
|
712
|
+
<span :class="['workbench-image-alert-ranking-severity', ...imageComposeAlertSeverityClasses(item)]">{{ imageComposeAlertRankingSeverity(item) }}</span>
|
|
713
|
+
<strong class="workbench-image-alert-ranking-title min-w-0 truncate text-sm text-[#f8efe9]" :title="imageComposeAlertRankingTitle(item, index)">{{ imageComposeAlertRankingTitle(item, index) }}</strong>
|
|
714
|
+
<time class="workbench-image-alert-ranking-time shrink-0 text-sm text-[#d7c0ba]" :title="imageComposeAlertRankingTime(item, index)">{{ imageComposeAlertRankingTime(item, index) }}</time>
|
|
715
|
+
</div>
|
|
716
|
+
</div>
|
|
717
|
+
</div>
|
|
718
|
+
<div
|
|
719
|
+
v-else-if="imageComposeBidConclusionCard(effectiveBlock, effectiveData)"
|
|
720
|
+
class="workbench-image-bid-conclusion grid h-full min-h-0 w-full grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-md border border-amber-200 bg-amber-50 px-3 py-2 text-xs leading-5"
|
|
721
|
+
>
|
|
722
|
+
<div class="grid min-w-0 grid-cols-[minmax(0,1fr)_auto_auto] items-center gap-2">
|
|
723
|
+
<strong class="min-w-0 truncate text-sm leading-5 text-slate-900" :title="effectiveBlock.title">{{ effectiveBlock.title }}</strong>
|
|
724
|
+
<span v-if="dataBindingNeedsHumanIntervention(effectiveBlock)" class="shrink-0 rounded bg-white px-1.5 py-0.5 text-xs font-semibold leading-5 text-amber-700">
|
|
725
|
+
{{ imageComposeBusinessGapBadgeLabel(effectiveBlock) }}
|
|
726
|
+
</span>
|
|
727
|
+
<span class="shrink-0 rounded bg-amber-100 px-2 py-0.5 text-xs font-semibold leading-5 text-amber-700">
|
|
728
|
+
{{ imageComposeBidConclusionBadge(effectiveData as CategoryRankingData) }}
|
|
729
|
+
</span>
|
|
730
|
+
</div>
|
|
731
|
+
<p class="mt-2 min-h-0 overflow-hidden text-sm leading-6 text-slate-700" :title="imageComposeBidConclusionDetail(effectiveData as CategoryRankingData)">
|
|
732
|
+
{{ imageComposeBidConclusionDetail(effectiveData as CategoryRankingData) }}
|
|
733
|
+
</p>
|
|
734
|
+
</div>
|
|
735
|
+
<div
|
|
736
|
+
v-else-if="imageComposeEmptyRankingPreview(effectiveBlock, effectiveData as CategoryRankingData)"
|
|
737
|
+
class="workbench-image-empty-ranking-preview flex h-full min-h-0 w-full flex-col overflow-hidden rounded-lg border border-slate-200 bg-white px-4 py-3 shadow-[0_2px_8px_rgba(15,23,42,0.04)]"
|
|
738
|
+
>
|
|
739
|
+
<div class="min-w-0">
|
|
740
|
+
<strong class="min-w-0 truncate text-sm leading-5 text-slate-900" :title="effectiveBlock.title">{{ effectiveBlock.title }}</strong>
|
|
741
|
+
</div>
|
|
742
|
+
<div class="workbench-image-empty-ranking-preview__body mt-3 grid min-h-0 flex-1 content-start gap-2 overflow-hidden">
|
|
743
|
+
<div
|
|
744
|
+
v-for="(item, index) in imageComposeRankingPreviewItems(effectiveBlock, effectiveData as CategoryRankingData)"
|
|
745
|
+
:key="`image-empty-ranking-preview-${effectiveBlock.id}-${index}-${imageComposeRankingPreviewLabel(item, index)}`"
|
|
746
|
+
class="grid min-w-0 grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-2"
|
|
747
|
+
>
|
|
748
|
+
<span :class="imageComposeRankingPreviewAvatarClass(item, index)">{{ imageComposeRankingPreviewAvatar(item, index) }}</span>
|
|
749
|
+
<span class="grid min-w-0 gap-1">
|
|
750
|
+
<strong class="min-w-0 truncate text-xs font-semibold leading-4 text-slate-800" :title="imageComposeRankingPreviewLabel(item, index)">
|
|
751
|
+
{{ imageComposeRankingPreviewLabel(item, index) }}
|
|
752
|
+
</strong>
|
|
753
|
+
<span v-if="imageComposeRankingPreviewDetail(item)" class="min-w-0 truncate text-[11px] leading-4 text-slate-400" :title="imageComposeRankingPreviewDetail(item)">
|
|
754
|
+
{{ imageComposeRankingPreviewDetail(item) }}
|
|
755
|
+
</span>
|
|
756
|
+
<span v-else class="h-1.5 w-16 rounded-full bg-slate-100" aria-hidden="true" />
|
|
757
|
+
</span>
|
|
758
|
+
<span :class="imageComposeRankingPreviewValueClass(item, index)">
|
|
759
|
+
{{ imageComposeRankingPreviewValue(item, effectiveData as CategoryRankingData) }}
|
|
760
|
+
</span>
|
|
761
|
+
</div>
|
|
762
|
+
</div>
|
|
763
|
+
<div class="workbench-image-empty-ranking-preview__action mt-3 flex shrink-0 justify-end">
|
|
764
|
+
<span class="inline-flex items-center gap-1 text-xs font-semibold leading-5 text-[#4c2cff]">View all <ArrowRight class="h-3.5 w-3.5" /></span>
|
|
765
|
+
</div>
|
|
766
|
+
</div>
|
|
767
|
+
<div
|
|
768
|
+
v-else-if="imageComposeCompactCard(effectiveBlock)"
|
|
769
|
+
class="workbench-image-empty-ranking-preview flex h-full min-h-0 w-full flex-col overflow-hidden rounded-lg border border-slate-200 bg-white px-4 py-3 shadow-[0_2px_8px_rgba(15,23,42,0.04)]"
|
|
770
|
+
>
|
|
771
|
+
<div class="min-w-0">
|
|
772
|
+
<strong class="min-w-0 truncate text-sm leading-5 text-slate-900" :title="effectiveBlock.title">{{ effectiveBlock.title }}</strong>
|
|
773
|
+
</div>
|
|
774
|
+
<div class="workbench-image-empty-ranking-preview__body mt-3 grid min-h-0 flex-1 content-start gap-2 overflow-hidden">
|
|
775
|
+
<div
|
|
776
|
+
v-for="(item, index) in imageComposeRankingPreviewItems(effectiveBlock, effectiveData as CategoryRankingData)"
|
|
777
|
+
:key="`image-ranking-preview-${effectiveBlock.id}-${index}-${imageComposeRankingPreviewLabel(item, index)}`"
|
|
778
|
+
class="grid min-w-0 grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-2"
|
|
779
|
+
>
|
|
780
|
+
<span :class="imageComposeRankingPreviewAvatarClass(item, index)">{{ imageComposeRankingPreviewAvatar(item, index) }}</span>
|
|
781
|
+
<span class="grid min-w-0 gap-1">
|
|
782
|
+
<strong class="min-w-0 truncate text-xs font-semibold leading-4 text-slate-800" :title="imageComposeRankingPreviewLabel(item, index)">
|
|
783
|
+
{{ imageComposeRankingPreviewLabel(item, index) }}
|
|
784
|
+
</strong>
|
|
785
|
+
<span v-if="imageComposeRankingPreviewDetail(item)" class="min-w-0 truncate text-[11px] leading-4 text-slate-400" :title="imageComposeRankingPreviewDetail(item)">
|
|
786
|
+
{{ imageComposeRankingPreviewDetail(item) }}
|
|
787
|
+
</span>
|
|
788
|
+
<span v-else class="h-1.5 w-16 rounded-full bg-slate-100" aria-hidden="true" />
|
|
789
|
+
</span>
|
|
790
|
+
<span :class="imageComposeRankingPreviewValueClass(item, index)">
|
|
791
|
+
{{ imageComposeRankingPreviewValue(item, effectiveData as CategoryRankingData) }}
|
|
792
|
+
</span>
|
|
793
|
+
</div>
|
|
794
|
+
</div>
|
|
795
|
+
<div class="workbench-image-empty-ranking-preview__action mt-3 flex shrink-0 justify-end">
|
|
796
|
+
<span class="inline-flex items-center gap-1 text-xs font-semibold leading-5 text-[#4c2cff]">View all <ArrowRight class="h-3.5 w-3.5" /></span>
|
|
797
|
+
</div>
|
|
798
|
+
</div>
|
|
799
|
+
<div v-else :class="['h-full min-h-0 w-full overflow-hidden', imageComposeCompactCard(effectiveBlock) ? 'space-y-2 px-3 py-2' : 'space-y-3']">
|
|
800
|
+
<div v-for="(item, index) in compactLimit((effectiveData as CategoryRankingData).items, 2, imageComposeCompactCard(effectiveBlock) ? 3 : 4)" :key="item.label" :class="imageComposeCompactCard(effectiveBlock) ? 'space-y-1' : 'space-y-2'">
|
|
801
|
+
<div class="flex items-center justify-between gap-2">
|
|
802
|
+
<div class="flex min-w-0 items-center gap-2">
|
|
803
|
+
<div
|
|
804
|
+
:class="[
|
|
805
|
+
'flex shrink-0 items-center justify-center text-xs font-semibold',
|
|
806
|
+
imageComposeCompactCard(effectiveBlock)
|
|
807
|
+
? ['h-6 w-6 rounded-full', index % 3 === 0 ? 'bg-[#4c2cff] text-white' : index % 3 === 1 ? 'bg-[#e9f8f5] text-[#0f9f8b]' : 'bg-[#fff3d6] text-[#d78b00]']
|
|
808
|
+
: 'h-7 w-7 rounded bg-slate-100 text-slate-600',
|
|
809
|
+
]"
|
|
810
|
+
>{{ imageComposeCompactCard(effectiveBlock) ? textValue((item as Record<string, unknown>).avatar, (item.label || String(index + 1)).slice(0, 1)).toUpperCase() : index + 1 }}</div>
|
|
811
|
+
<div>
|
|
812
|
+
<div class="truncate font-medium text-slate-900" :class="imageComposeCompactCard(effectiveBlock) ? 'text-[11px]' : ''">{{ item.label }}</div>
|
|
813
|
+
<div v-if="density !== 'thumbnail' && item.badge && !imageComposeCompactCard(effectiveBlock)" class="text-[11px] text-slate-500">{{ item.badge }}</div>
|
|
814
|
+
<div v-if="imageComposeCompactCard(effectiveBlock)" class="mt-0.5 h-1.5 w-16 rounded-full bg-slate-100" />
|
|
815
|
+
</div>
|
|
816
|
+
</div>
|
|
817
|
+
<div class="text-right">
|
|
818
|
+
<div class="font-semibold text-slate-900" :class="imageComposeCompactCard(effectiveBlock) ? 'text-[11px]' : ''">{{ textValue((item as Record<string, unknown>).valueLabel) || formatMetricValue(item.value, (effectiveData as CategoryRankingData).valueFormat) }}</div>
|
|
819
|
+
<div v-if="density !== 'thumbnail' && !imageComposeCompactCard(effectiveBlock)" class="text-[11px] text-slate-500">{{ (item.share * 100).toFixed(1) }}%</div>
|
|
820
|
+
</div>
|
|
821
|
+
</div>
|
|
822
|
+
<div v-if="!imageComposeCompactCard(effectiveBlock)" class="h-2 rounded-full bg-slate-100"><div class="h-2 rounded-full bg-gradient-to-r from-[#1f4fd4] to-[#6fa9ff]" :style="{ width: `${Math.max(6, item.share * 100)}%` }" /></div>
|
|
823
|
+
</div>
|
|
824
|
+
</div>
|
|
825
|
+
</template>
|
|
826
|
+
|
|
827
|
+
<template v-else-if="effectiveData?.shape === 'rows'">
|
|
828
|
+
<div
|
|
829
|
+
v-if="imageComposeBidRowsCard(effectiveBlock, effectiveData)"
|
|
830
|
+
class="workbench-image-bid-rows-card grid h-full min-h-0 w-full grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-md border border-slate-200 bg-white text-xs leading-5"
|
|
831
|
+
>
|
|
832
|
+
<div class="grid h-9 shrink-0 grid-cols-[auto_minmax(0,1fr)_minmax(0,14rem)] items-center gap-2 border-b border-slate-200 bg-slate-50 px-3">
|
|
833
|
+
<i class="h-4 w-1.5 rounded-full bg-emerald-600" />
|
|
834
|
+
<strong class="min-w-0 truncate text-sm leading-5 text-slate-900" :title="effectiveBlock.title">{{ effectiveBlock.title }}</strong>
|
|
835
|
+
<span class="min-w-0 truncate text-right text-xs font-semibold text-slate-500" :title="effectiveBlock.subtitle">{{ effectiveBlock.subtitle }}</span>
|
|
836
|
+
</div>
|
|
837
|
+
|
|
838
|
+
<div
|
|
839
|
+
v-if="imageComposeBidRowsVisualKind(effectiveBlock, effectiveData) === 'infoGrid'"
|
|
840
|
+
class="grid min-h-0 content-start gap-2 overflow-hidden p-2"
|
|
841
|
+
:style="imageComposeBidTargetInfoGridStyle(imageComposeBidInfoItems(effectiveData).length)"
|
|
842
|
+
>
|
|
843
|
+
<div
|
|
844
|
+
v-for="(item, index) in imageComposeBidInfoItems(effectiveData).slice(0, 9)"
|
|
845
|
+
:key="`${item.label}-${item.value}`"
|
|
846
|
+
:class="[imageComposeBidInfoTileClasses(imageComposeBidInfoItems(effectiveData).length), imageComposeBidPanelClasses(item.record)]"
|
|
847
|
+
:style="imageComposeBidInfoTilePlacementStyle(index, imageComposeBidInfoItems(effectiveData).slice(0, 9).length)"
|
|
848
|
+
:title="`${item.label}:${item.value}`"
|
|
849
|
+
>
|
|
850
|
+
<span :class="imageComposeBidInfoLabelClasses(imageComposeBidInfoItems(effectiveData).length)">{{ item.label }}</span>
|
|
851
|
+
<b :class="imageComposeBidInfoValueClasses(imageComposeBidInfoItems(effectiveData).length)">{{ item.value }}</b>
|
|
852
|
+
</div>
|
|
853
|
+
</div>
|
|
854
|
+
|
|
855
|
+
<div
|
|
856
|
+
v-else-if="imageComposeBidRowsVisualKind(effectiveBlock, effectiveData) === 'cardGrid'"
|
|
857
|
+
class="grid min-h-0 content-start gap-2 overflow-hidden p-2"
|
|
858
|
+
:style="imageComposeBidCardGridStyle(imageComposeBidRowCards(effectiveData).length)"
|
|
859
|
+
>
|
|
860
|
+
<div
|
|
861
|
+
v-for="item in imageComposeBidRowCards(effectiveData).slice(0, 8)"
|
|
862
|
+
:key="`${item.label}-${item.value}`"
|
|
863
|
+
:class="[imageComposeBidCardTileClasses(imageComposeBidRowCards(effectiveData).length), imageComposeBidPanelClasses(item.record)]"
|
|
864
|
+
:title="[item.label, item.value, item.detail].filter(Boolean).join(' · ')"
|
|
865
|
+
>
|
|
866
|
+
<strong class="truncate text-sm leading-5 text-slate-900">{{ item.label }}</strong>
|
|
867
|
+
<span :class="[imageComposeBidCardPillPlacementClasses(imageComposeBidRowCards(effectiveData).length), imageComposeBidPillClasses(item.record)]">{{ item.value }}</span>
|
|
868
|
+
<span v-if="imageComposeBidRowCards(effectiveData).length < 7" class="mt-1 max-h-10 overflow-hidden leading-5 text-slate-600">{{ item.detail }}</span>
|
|
869
|
+
</div>
|
|
870
|
+
</div>
|
|
871
|
+
|
|
872
|
+
<div v-else class="grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden">
|
|
873
|
+
<div class="grid border-b border-slate-200 bg-slate-50 px-3 py-1.5 font-semibold text-slate-500" :style="imageComposeBidRowsGridStyle(imageComposeBidRowsColumns(effectiveData))">
|
|
874
|
+
<span v-for="column in imageComposeBidRowsColumns(effectiveData)" :key="column" class="truncate">{{ column }}</span>
|
|
875
|
+
</div>
|
|
876
|
+
<div class="min-h-0 overflow-hidden">
|
|
877
|
+
<div
|
|
878
|
+
v-for="(row, rowIndex) in imageComposeBidRowsRecords(effectiveData).slice(0, 6)"
|
|
879
|
+
:key="`bid-row-${rowIndex}`"
|
|
880
|
+
:class="['grid min-h-0 items-center border-b border-slate-100 px-3 py-1.5 last:border-b-0', imageComposeBidPanelClasses(row)]"
|
|
881
|
+
:style="imageComposeBidRowsGridStyle(imageComposeBidRowsColumns(effectiveData))"
|
|
882
|
+
:title="imageComposeBidRowsColumns(effectiveData).map((column) => `${column}:${imageComposeBidRowsCell(row, column)}`).join(' · ')"
|
|
883
|
+
>
|
|
884
|
+
<span
|
|
885
|
+
v-for="column in imageComposeBidRowsColumns(effectiveData)"
|
|
886
|
+
:key="column"
|
|
887
|
+
class="min-w-0 truncate font-semibold text-slate-700"
|
|
888
|
+
>
|
|
889
|
+
{{ imageComposeBidRowsCell(row, column) }}
|
|
890
|
+
</span>
|
|
891
|
+
</div>
|
|
892
|
+
</div>
|
|
893
|
+
</div>
|
|
894
|
+
</div>
|
|
895
|
+
<div
|
|
896
|
+
v-else-if="tableRowsPreviewCard(effectiveBlock, effectiveData)"
|
|
897
|
+
class="grid h-full min-h-0 w-full grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-md border border-slate-100 bg-white text-xs leading-5"
|
|
898
|
+
>
|
|
899
|
+
<div class="flex h-9 shrink-0 items-center justify-between gap-2 border-b border-slate-100 bg-slate-50 px-3">
|
|
900
|
+
<strong class="min-w-0 truncate text-sm text-slate-900" :title="effectiveBlock.title">{{ effectiveBlock.title }}</strong>
|
|
901
|
+
<span class="shrink-0 text-[11px] font-semibold text-slate-400">{{ ((effectiveData as TableRowsData).rows || []).length }} 行</span>
|
|
902
|
+
</div>
|
|
903
|
+
|
|
904
|
+
<div
|
|
905
|
+
v-if="['tableParameter', 'tableDescription'].includes(tableRowsPreviewVisualKind(effectiveData, effectiveBlock))"
|
|
906
|
+
class="grid min-h-0 content-start gap-1 overflow-y-auto p-1.5"
|
|
907
|
+
:style="{ gridTemplateColumns: 'repeat(2, minmax(0, 1fr))' }"
|
|
908
|
+
>
|
|
909
|
+
<div
|
|
910
|
+
v-for="row in tableRowsPreviewRecords(effectiveData)"
|
|
911
|
+
:key="row.id"
|
|
912
|
+
class="grid min-h-[36px] grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-md border border-slate-200 bg-slate-50 px-2 py-1"
|
|
913
|
+
>
|
|
914
|
+
<span class="truncate text-[11px] font-semibold leading-4 text-slate-500" :title="tableRowsPreviewCell(row, ((effectiveData as TableRowsData).columns || [])[0])">{{ tableRowsPreviewCell(row, ((effectiveData as TableRowsData).columns || [])[0]) }}</span>
|
|
915
|
+
<b class="truncate text-[13px] font-semibold leading-5 text-slate-900" :title="tableRowsPreviewCell(row, ((effectiveData as TableRowsData).columns || [])[1])">{{ tableRowsPreviewCell(row, ((effectiveData as TableRowsData).columns || [])[1]) }}</b>
|
|
916
|
+
</div>
|
|
917
|
+
</div>
|
|
918
|
+
|
|
919
|
+
<div
|
|
920
|
+
v-else-if="['tableTimeline', 'tableSteps'].includes(tableRowsPreviewVisualKind(effectiveData, effectiveBlock))"
|
|
921
|
+
class="min-h-0 overflow-y-auto p-2"
|
|
922
|
+
>
|
|
923
|
+
<div
|
|
924
|
+
v-for="(row, rowIndex) in tableRowsPreviewRecords(effectiveData)"
|
|
925
|
+
:key="row.id"
|
|
926
|
+
class="grid grid-cols-[1.75rem_minmax(0,1fr)_auto] items-center gap-2 border-b border-slate-100 py-1.5 last:border-b-0"
|
|
927
|
+
>
|
|
928
|
+
<span class="grid h-6 w-6 place-items-center rounded-full bg-[#edf1ff] text-[11px] font-semibold text-[#4C78FC]">
|
|
929
|
+
{{ rowIndex + 1 }}
|
|
930
|
+
</span>
|
|
931
|
+
<span class="min-w-0 truncate font-semibold text-slate-800">{{ tableRowsTimelinePrimaryCell(row, ((effectiveData as TableRowsData).columns || [])) }}</span>
|
|
932
|
+
<span class="shrink-0 rounded bg-slate-100 px-1.5 py-0.5 text-[11px] font-medium text-slate-500">
|
|
933
|
+
{{ tableRowsTimelineBadgeCell(row, ((effectiveData as TableRowsData).columns || [])) }}
|
|
934
|
+
</span>
|
|
935
|
+
</div>
|
|
936
|
+
</div>
|
|
937
|
+
|
|
938
|
+
<div v-else class="min-h-0 overflow-hidden">
|
|
939
|
+
<ATable
|
|
940
|
+
class="workbench-card-ant-table h-full"
|
|
941
|
+
size="small"
|
|
942
|
+
row-key="__rowKey"
|
|
943
|
+
:columns="tableRowsPreviewAntTableColumns(effectiveBlock.id, (effectiveData as TableRowsData).columns || [])"
|
|
944
|
+
:data-source="tableRowsPreviewAntTableRows(effectiveData, (effectiveData as TableRowsData).columns || [])"
|
|
945
|
+
:pagination="false"
|
|
946
|
+
:scroll="tableRowsAntTableScroll(tableRowsPreviewAntTableColumns(effectiveBlock.id, (effectiveData as TableRowsData).columns || []))"
|
|
947
|
+
@resize-column="handleTableRowsAntTableColumnResize"
|
|
948
|
+
/>
|
|
949
|
+
</div>
|
|
950
|
+
</div>
|
|
951
|
+
<div v-else class="grid h-full min-h-0 w-full grid-rows-[auto_minmax(0,1fr)] overflow-hidden border border-slate-100">
|
|
952
|
+
<ATable
|
|
953
|
+
class="workbench-card-ant-table h-full"
|
|
954
|
+
size="small"
|
|
955
|
+
row-key="__rowKey"
|
|
956
|
+
:columns="tableRowsFallbackAntTableColumns(effectiveBlock.id, effectiveData as TableRowsData)"
|
|
957
|
+
:data-source="tableRowsFallbackAntTableRows(effectiveData as TableRowsData)"
|
|
958
|
+
:pagination="false"
|
|
959
|
+
:scroll="tableRowsAntTableScroll(tableRowsFallbackAntTableColumns(effectiveBlock.id, effectiveData as TableRowsData))"
|
|
960
|
+
@resize-column="handleTableRowsAntTableColumnResize"
|
|
961
|
+
/>
|
|
962
|
+
</div>
|
|
963
|
+
</template>
|
|
964
|
+
|
|
965
|
+
<template v-else-if="effectiveData?.shape === 'insightNarrative'">
|
|
966
|
+
<div class="h-full min-h-0 w-full space-y-4 overflow-y-auto">
|
|
967
|
+
<div class="flex items-center gap-2 text-sm font-semibold text-slate-900"><Sparkles class="h-4 w-4 text-[#1f4fd4]" /><span>AI 经营判断</span></div>
|
|
968
|
+
<div class="space-y-3">
|
|
969
|
+
<div v-for="item in compactLimit((effectiveData as InsightNarrativeData).bullets, 1, 2)" :key="item" class="flex items-center gap-3 rounded-lg border border-slate-100 bg-slate-50/80 p-3">
|
|
970
|
+
<div class="h-2.5 w-2.5 shrink-0 rounded-full bg-[#1f4fd4]" />
|
|
971
|
+
<p class="text-sm leading-6 text-slate-700">{{ item }}</p>
|
|
972
|
+
</div>
|
|
973
|
+
</div>
|
|
974
|
+
<div v-if="density !== 'thumbnail'" class="flex items-center justify-between text-xs text-slate-500">
|
|
975
|
+
<span>{{ (effectiveData as InsightNarrativeData).owner || 'Workbench AI' }}</span>
|
|
976
|
+
<span v-if="typeof (effectiveData as InsightNarrativeData).confidence === 'number'">置信度 {{ (((effectiveData as InsightNarrativeData).confidence || 0) * 100).toFixed(0) }}%</span>
|
|
977
|
+
</div>
|
|
978
|
+
</div>
|
|
979
|
+
</template>
|
|
980
|
+
|
|
981
|
+
<template v-else-if="effectiveData?.shape === 'taskSummary'">
|
|
982
|
+
<div class="h-full min-h-0 w-full space-y-4 overflow-y-auto">
|
|
983
|
+
<div v-if="density !== 'thumbnail'" class="grid grid-cols-4 gap-2">
|
|
984
|
+
<div v-for="item in [['全部', (effectiveData as TaskSummaryData).total], ['今日', (effectiveData as TaskSummaryData).dueToday], ['逾期', (effectiveData as TaskSummaryData).overdue], ['完成', (effectiveData as TaskSummaryData).completed]]" :key="String(item[0])" class="rounded-lg border border-slate-100 bg-slate-50/80 px-3 py-2">
|
|
985
|
+
<div class="text-[11px] text-slate-500">{{ item[0] }}</div>
|
|
986
|
+
<div class="mt-1 text-lg font-semibold text-slate-900">{{ item[1] }}</div>
|
|
987
|
+
</div>
|
|
988
|
+
</div>
|
|
989
|
+
<div class="space-y-2">
|
|
990
|
+
<div v-for="item in compactLimit((effectiveData as TaskSummaryData).items, 2, 3)" :key="item.id" class="rounded-lg border border-slate-100 bg-white px-3 py-2">
|
|
991
|
+
<div class="flex items-start justify-between gap-3">
|
|
992
|
+
<div class="min-w-0">
|
|
993
|
+
<div class="truncate text-sm font-semibold text-slate-900">{{ item.title }}</div>
|
|
994
|
+
<div v-if="density !== 'thumbnail'" class="mt-1 text-[11px] text-slate-500">{{ item.source || (effectiveData as TaskSummaryData).sourceLabel }}{{ item.dueAt ? ` · 截止 ${item.dueAt}` : '' }}</div>
|
|
995
|
+
</div>
|
|
996
|
+
<div class="flex shrink-0 gap-1">
|
|
997
|
+
<span class="rounded-full bg-slate-100 px-2 py-0.5 text-xs text-slate-600">{{ taskTypeLabel(item.type) }}</span>
|
|
998
|
+
<span :class="['rounded-full px-2 py-0.5 text-xs', taskStatusClass(item.status)]">{{ taskStatusLabel(item.status) }}</span>
|
|
999
|
+
</div>
|
|
1000
|
+
</div>
|
|
1001
|
+
</div>
|
|
1002
|
+
</div>
|
|
1003
|
+
</div>
|
|
1004
|
+
</template>
|
|
1005
|
+
|
|
1006
|
+
<template v-else-if="effectiveData?.shape === 'weatherCurrent'">
|
|
1007
|
+
<div class="h-full min-h-0 w-full space-y-3 overflow-y-auto">
|
|
1008
|
+
<div class="rounded-lg border border-sky-100 bg-gradient-to-br from-sky-50 via-white to-emerald-50 p-3">
|
|
1009
|
+
<div class="flex items-start justify-between gap-3">
|
|
1010
|
+
<div class="min-w-0">
|
|
1011
|
+
<div class="truncate text-xs font-medium text-slate-500">{{ (effectiveData as WeatherCurrentData).location }}</div>
|
|
1012
|
+
<div class="mt-2 flex items-end gap-2">
|
|
1013
|
+
<span :class="density === 'thumbnail' || density === 'compact' ? 'text-3xl' : 'text-5xl'" class="font-semibold text-slate-950">{{ formatWeatherTemp((effectiveData as WeatherCurrentData).temperatureC) }}</span>
|
|
1014
|
+
<span class="pb-1 text-sm font-medium text-slate-600">{{ (effectiveData as WeatherCurrentData).conditionLabel }}</span>
|
|
1015
|
+
</div>
|
|
1016
|
+
</div>
|
|
1017
|
+
<div class="flex h-12 w-12 shrink-0 items-center justify-center rounded-lg bg-white text-sky-600 shadow-sm shadow-sky-100">
|
|
1018
|
+
<component :is="weatherIcon((effectiveData as WeatherCurrentData).condition)" class="h-6 w-6" />
|
|
1019
|
+
</div>
|
|
1020
|
+
</div>
|
|
1021
|
+
</div>
|
|
1022
|
+
<div v-if="density !== 'thumbnail'" class="grid grid-cols-2 gap-2">
|
|
1023
|
+
<div class="rounded-lg border border-slate-100 bg-slate-50/70 px-3 py-2"><div class="flex items-center gap-1.5 text-[11px] text-slate-500"><ThermometerSun class="h-3.5 w-3.5" />体感</div><div class="mt-1 text-sm font-semibold text-slate-900">{{ formatWeatherTemp((effectiveData as WeatherCurrentData).feelsLikeC) }}</div></div>
|
|
1024
|
+
<div class="rounded-lg border border-slate-100 bg-slate-50/70 px-3 py-2"><div class="flex items-center gap-1.5 text-[11px] text-slate-500"><Droplets class="h-3.5 w-3.5" />湿度</div><div class="mt-1 text-sm font-semibold text-slate-900">{{ typeof (effectiveData as WeatherCurrentData).humidityPct === 'number' ? `${(effectiveData as WeatherCurrentData).humidityPct}%` : '--' }}</div></div>
|
|
1025
|
+
<div class="rounded-lg border border-slate-100 bg-slate-50/70 px-3 py-2"><div class="flex items-center gap-1.5 text-[11px] text-slate-500"><CloudRain class="h-3.5 w-3.5" />降雨</div><div class="mt-1 text-sm font-semibold text-slate-900">{{ typeof (effectiveData as WeatherCurrentData).precipitationPct === 'number' ? `${(effectiveData as WeatherCurrentData).precipitationPct}%` : '--' }}</div></div>
|
|
1026
|
+
<div class="rounded-lg border border-slate-100 bg-slate-50/70 px-3 py-2"><div class="flex items-center gap-1.5 text-[11px] text-slate-500"><Wind class="h-3.5 w-3.5" />风力</div><div class="mt-1 text-sm font-semibold text-slate-900">{{ (effectiveData as WeatherCurrentData).wind ? `${(effectiveData as WeatherCurrentData).wind?.direction} ${(effectiveData as WeatherCurrentData).wind?.level}` : '--' }}</div></div>
|
|
1027
|
+
</div>
|
|
1028
|
+
<div class="grid gap-2" :style="{ gridTemplateColumns: `repeat(${Math.max(1, compactLimit((effectiveData as WeatherCurrentData).forecast, 2, 2).length)}, minmax(0, 1fr))` }">
|
|
1029
|
+
<div v-for="item in compactLimit((effectiveData as WeatherCurrentData).forecast, 2, 2)" :key="item.label" class="rounded-lg border border-slate-100 bg-white px-2 py-2 text-center">
|
|
1030
|
+
<div class="text-[11px] font-medium text-slate-500">{{ item.label }}</div>
|
|
1031
|
+
<div class="mt-1 text-xs text-slate-600">{{ item.conditionLabel }}</div>
|
|
1032
|
+
<div class="mt-1 text-xs font-semibold text-slate-900">{{ formatWeatherTemp(item.lowC) }} / {{ formatWeatherTemp(item.highC) }}</div>
|
|
1033
|
+
</div>
|
|
1034
|
+
</div>
|
|
1035
|
+
</div>
|
|
1036
|
+
</template>
|
|
1037
|
+
|
|
1038
|
+
<template v-else-if="effectiveData?.shape === 'dashboardGrid'">
|
|
1039
|
+
<div class="flex h-full min-h-0 w-full flex-col overflow-hidden">
|
|
1040
|
+
<div
|
|
1041
|
+
class="grid min-h-0 flex-1 grid-cols-2 gap-2"
|
|
1042
|
+
:style="{ gridTemplateRows: `repeat(${Math.max(1, Math.ceil((effectiveData as DashboardGridData).panels.length / 2))}, minmax(0, 1fr))` }"
|
|
1043
|
+
>
|
|
1044
|
+
<div v-for="panel in (effectiveData as DashboardGridData).panels" :key="panel.id" class="flex min-h-0 min-w-0 flex-col overflow-hidden border border-slate-100 bg-slate-50/70 px-2 py-2">
|
|
1045
|
+
<div class="mb-1 flex shrink-0 items-center justify-between gap-2">
|
|
1046
|
+
<div class="min-w-0"><div class="truncate text-xs font-semibold text-slate-900">{{ panel.title }}</div><div v-if="density === 'expanded' && panel.subtitle" class="truncate text-xs text-slate-500">{{ panel.subtitle }}</div></div>
|
|
1047
|
+
<FileBarChart2 class="h-3.5 w-3.5 shrink-0 text-[#1f4fd4]" />
|
|
1048
|
+
</div>
|
|
1049
|
+
<div class="min-h-0 flex-1 overflow-hidden"><ChartRegistryRenderer :renderer-key="panel.rendererKey" :data="panel.data" :card-title="panel.title" :role-id="roleId" :user-id="userId" density="thumbnail" :refresh-runtime="chartRefreshRuntime" /></div>
|
|
1050
|
+
</div>
|
|
1051
|
+
</div>
|
|
1052
|
+
<div v-if="density === 'expanded'" class="mt-2 shrink-0 border border-slate-100 bg-white px-3 py-1.5 text-xs leading-5 text-slate-600">{{ (effectiveData as DashboardGridData).narrative }}</div>
|
|
1053
|
+
</div>
|
|
1054
|
+
</template>
|
|
1055
|
+
|
|
1056
|
+
<template v-else-if="effectiveData?.shape === 'calendarCard'">
|
|
1057
|
+
<div class="h-full min-h-0 w-full space-y-3 overflow-y-auto">
|
|
1058
|
+
<div class="flex items-center justify-between gap-3">
|
|
1059
|
+
<div><div class="text-lg font-semibold text-slate-900">{{ (effectiveData as CalendarCardData).dateLabel }}</div><div class="text-xs text-slate-500">{{ (effectiveData as CalendarCardData).weekLabel }} · {{ (effectiveData as CalendarCardData).timezone }}</div></div>
|
|
1060
|
+
<div class="flex h-10 w-10 items-center justify-center rounded-xl bg-[#edf3ff] text-[#1f4fd4]"><CalendarDays class="h-5 w-5" /></div>
|
|
1061
|
+
</div>
|
|
1062
|
+
<div class="space-y-2">
|
|
1063
|
+
<div v-for="item in compactLimit((effectiveData as CalendarCardData).items, 2, 2)" :key="item.id" class="flex items-center justify-between gap-3 rounded-lg border border-slate-100 bg-slate-50/80 px-3 py-2">
|
|
1064
|
+
<div class="min-w-0"><div class="truncate text-sm font-medium text-slate-800">{{ item.title }}</div><div v-if="density !== 'thumbnail'" class="text-[11px] text-slate-500">{{ item.type }}</div></div>
|
|
1065
|
+
<span class="shrink-0 text-xs font-semibold text-slate-600">{{ item.time }}</span>
|
|
1066
|
+
</div>
|
|
1067
|
+
</div>
|
|
1068
|
+
</div>
|
|
1069
|
+
</template>
|
|
1070
|
+
|
|
1071
|
+
<template v-else-if="effectiveData?.shape === 'reportSummary'">
|
|
1072
|
+
<div class="h-full min-h-0 w-full space-y-3 overflow-y-auto">
|
|
1073
|
+
<p class="text-sm leading-6 text-slate-700">{{ (effectiveData as ReportSummaryDisplayData).summary }}</p>
|
|
1074
|
+
<div class="space-y-2">
|
|
1075
|
+
<div v-for="item in compactLimit((effectiveData as ReportSummaryDisplayData).highlights, 1, 2)" :key="item" class="rounded-lg border border-slate-100 bg-slate-50 px-3 py-2 text-sm leading-6 text-slate-700">{{ item }}</div>
|
|
1076
|
+
</div>
|
|
1077
|
+
<div v-if="density !== 'thumbnail'" class="text-[11px] text-slate-500">{{ (effectiveData as ReportSummaryDisplayData).sourceLabel }}</div>
|
|
1078
|
+
</div>
|
|
1079
|
+
</template>
|
|
1080
|
+
|
|
1081
|
+
<template v-else-if="effectiveData?.shape === 'embeddedFrame'">
|
|
1082
|
+
<div v-if="!(effectiveData as EmbeddedFrameData).srcUrl || (effectiveData as EmbeddedFrameData).status === 'blocked'" class="rounded-lg border border-dashed border-amber-200 bg-amber-50 px-4 py-5 text-sm leading-6 text-amber-800">
|
|
1083
|
+
{{ (effectiveData as EmbeddedFrameData).fallbackText || '缺少可嵌入页面地址。' }}
|
|
1084
|
+
</div>
|
|
1085
|
+
<div v-else class="flex h-full min-h-0 w-full flex-col overflow-hidden border border-slate-100 bg-white">
|
|
1086
|
+
<iframe :title="(effectiveData as EmbeddedFrameData).title" :src="(effectiveData as EmbeddedFrameData).srcUrl" :sandbox="(effectiveData as EmbeddedFrameData).sandbox" class="min-h-0 w-full flex-1 border-0" />
|
|
1087
|
+
<div class="border-t border-slate-100 px-3 py-2 text-[11px] text-slate-500">{{ (effectiveData as EmbeddedFrameData).sourceLabel }}</div>
|
|
1088
|
+
</div>
|
|
1089
|
+
</template>
|
|
1090
|
+
|
|
1091
|
+
<template v-else-if="effectiveData?.shape === 'fdeCustomComponent'">
|
|
1092
|
+
<component
|
|
1093
|
+
:is="fdeCustomComponentRenderState.component"
|
|
1094
|
+
v-if="fdeCustomComponentRenderState.component && fdeCustomComponentRenderState.status === 'ready'"
|
|
1095
|
+
v-bind="fdeCustomComponentRenderState.componentProps"
|
|
1096
|
+
/>
|
|
1097
|
+
<div v-else class="h-full min-h-0 w-full overflow-y-auto border border-slate-100 bg-slate-50/80 p-4">
|
|
1098
|
+
<div class="flex items-start justify-between gap-3">
|
|
1099
|
+
<div><div class="text-sm font-semibold text-slate-900">{{ (effectiveData as FdeCustomComponentData).componentName }}</div><div class="mt-1 text-xs text-slate-500">{{ (effectiveData as FdeCustomComponentData).componentRef }}</div></div>
|
|
1100
|
+
<span :class="fdeCustomComponentRenderState.status === 'ready' ? 'bg-emerald-50 text-emerald-700' : 'bg-amber-50 text-amber-700'" class="rounded-full px-2 py-0.5 text-[11px]">{{ fdeCustomComponentRenderState.status }}</span>
|
|
1101
|
+
</div>
|
|
1102
|
+
<p class="mt-3 text-xs leading-5 text-slate-500">{{ fdeCustomComponentRenderState.message || (effectiveData as FdeCustomComponentData).fallbackText || (effectiveData as FdeCustomComponentData).sourceLabel }}</p>
|
|
1103
|
+
</div>
|
|
1104
|
+
</template>
|
|
1105
|
+
|
|
1106
|
+
<template v-else-if="effectiveData?.shape === 'customCanvas' || effectiveData?.shape === 'geoGlobe'">
|
|
1107
|
+
<div v-if="effectiveData?.shape === 'geoGlobe'" class="space-y-3">
|
|
1108
|
+
<div class="relative overflow-hidden rounded-lg border border-slate-100 bg-[#07111f] p-4 text-white">
|
|
1109
|
+
<div class="absolute inset-0 opacity-60" style="background: radial-gradient(circle at 50% 45%, #2563eb 0, #0f766e 26%, #0f172a 58%)" />
|
|
1110
|
+
<div class="relative z-10 flex min-h-[120px] flex-col justify-between">
|
|
1111
|
+
<div><div class="text-sm font-semibold">{{ (effectiveData as GeoGlobeData).title }}</div><div class="mt-1 text-xs text-slate-200">{{ (effectiveData as GeoGlobeData).centerLabel }}</div></div>
|
|
1112
|
+
<div class="grid grid-cols-3 gap-2">
|
|
1113
|
+
<div v-for="item in (effectiveData as GeoGlobeData).metrics" :key="item.label" class="rounded-lg bg-white/10 px-2 py-2 backdrop-blur"><div class="text-xs text-slate-300">{{ item.label }}</div><div class="mt-1 text-sm font-semibold">{{ item.value }}</div></div>
|
|
1114
|
+
</div>
|
|
1115
|
+
</div>
|
|
1116
|
+
</div>
|
|
1117
|
+
</div>
|
|
1118
|
+
<div v-else :class="customCanvasShellClasses(effectiveBlock)" :style="customCanvasStyle(effectiveBlock, effectiveData as CustomCanvasData)">
|
|
1119
|
+
<div
|
|
1120
|
+
v-if="customCanvasEmptyPageHeaderPlaceholder(effectiveBlock, effectiveData as CustomCanvasData)"
|
|
1121
|
+
class="workbench-custom-canvas-page-header workbench-custom-canvas-page-header--placeholder pointer-events-none h-full min-h-0 w-full overflow-hidden"
|
|
1122
|
+
:style="customCanvasPageHeaderStyle(effectiveBlock, effectiveData as CustomCanvasData)"
|
|
1123
|
+
aria-hidden="true"
|
|
1124
|
+
/>
|
|
1125
|
+
<div
|
|
1126
|
+
v-else-if="customCanvasPageHeaderBlock(effectiveBlock, effectiveData as CustomCanvasData)"
|
|
1127
|
+
class="workbench-custom-canvas-page-header grid h-full min-h-0 w-full grid-cols-[minmax(0,1fr)_auto] items-center gap-3 overflow-hidden rounded-md border px-4 py-0"
|
|
1128
|
+
:style="customCanvasPageHeaderStyle(effectiveBlock, effectiveData as CustomCanvasData)"
|
|
1129
|
+
>
|
|
1130
|
+
<div class="workbench-custom-canvas-page-header__brand grid min-w-0 items-center gap-3 overflow-hidden">
|
|
1131
|
+
<span class="workbench-custom-canvas-page-header__logo grid shrink-0 place-items-center rounded font-semibold leading-none" :style="customCanvasHeaderLogoStyle(effectiveBlock, effectiveData as CustomCanvasData)" :title="customCanvasHeaderLogo(effectiveBlock, effectiveData as CustomCanvasData)">
|
|
1132
|
+
{{ customCanvasHeaderLogo(effectiveBlock, effectiveData as CustomCanvasData) }}
|
|
1133
|
+
</span>
|
|
1134
|
+
<div class="grid min-h-0 min-w-0 content-center">
|
|
1135
|
+
<h3 :class="['workbench-custom-canvas-page-header__title truncate font-semibold', customCanvasPageHeaderTextClass(effectiveBlock, effectiveData as CustomCanvasData, 'title')]" :title="customCanvasHeaderTitle(effectiveBlock, effectiveData as CustomCanvasData)">
|
|
1136
|
+
{{ customCanvasHeaderTitle(effectiveBlock, effectiveData as CustomCanvasData) }}
|
|
1137
|
+
</h3>
|
|
1138
|
+
<p
|
|
1139
|
+
v-if="customCanvasHeaderSubtitle(effectiveBlock, effectiveData as CustomCanvasData)"
|
|
1140
|
+
:class="['workbench-custom-canvas-page-header__subtitle truncate', customCanvasPageHeaderTextClass(effectiveBlock, effectiveData as CustomCanvasData, 'subtitle')]"
|
|
1141
|
+
:title="customCanvasHeaderSubtitle(effectiveBlock, effectiveData as CustomCanvasData)"
|
|
1142
|
+
>
|
|
1143
|
+
{{ customCanvasHeaderSubtitle(effectiveBlock, effectiveData as CustomCanvasData) }}
|
|
1144
|
+
</p>
|
|
1145
|
+
</div>
|
|
1146
|
+
</div>
|
|
1147
|
+
<div class="workbench-custom-canvas-page-header__actions flex min-w-0 items-center justify-end gap-2 overflow-hidden">
|
|
1148
|
+
<span
|
|
1149
|
+
v-for="pill in customCanvasHeaderPillsWithFallback(effectiveBlock, effectiveData as CustomCanvasData)"
|
|
1150
|
+
:key="pill"
|
|
1151
|
+
:class="['workbench-custom-canvas-page-header__pill shrink-0 truncate rounded border font-semibold', customCanvasPageHeaderTextClass(effectiveBlock, effectiveData as CustomCanvasData, 'pill')]"
|
|
1152
|
+
:title="pill"
|
|
1153
|
+
>
|
|
1154
|
+
{{ pill }}
|
|
1155
|
+
</span>
|
|
1156
|
+
</div>
|
|
1157
|
+
<span
|
|
1158
|
+
v-for="(nestedBlock, index) in customCanvasVisibleNestedBlocks(effectiveData as CustomCanvasData)"
|
|
1159
|
+
:key="`page-header-diagnostic-${nestedBlock.id}`"
|
|
1160
|
+
data-testid="workbench-nested-card-preview"
|
|
1161
|
+
:data-parent-block-id="effectiveBlock.id"
|
|
1162
|
+
:data-nested-block-id="nestedBlock.id"
|
|
1163
|
+
:data-nested-card-id="nestedBlock.id"
|
|
1164
|
+
:data-nested-card-title="nestedBlock.title"
|
|
1165
|
+
:data-nested-card-kind="nestedBlock.kind"
|
|
1166
|
+
:data-capability-id="nestedBlock.capabilityId"
|
|
1167
|
+
:data-compose-source="nestedBlockComposeSource(nestedBlock)"
|
|
1168
|
+
:data-binding-id="nestedBlock.dataBindingId || nestedBlock.dataBinding?.bindingId || nestedBlock.dataBinding?.id || ''"
|
|
1169
|
+
:data-binding-status="nestedBlock.dataBindingStatus"
|
|
1170
|
+
:data-renderer-key="nestedBlockRendererKey(nestedBlock)"
|
|
1171
|
+
:data-data-shape="nestedBlock.dataShape"
|
|
1172
|
+
:data-visual-kind="nestedBlockVisualKind(nestedBlock)"
|
|
1173
|
+
:data-business-gap="nestedBlockNeedsHumanIntervention(nestedBlock) ? 'true' : undefined"
|
|
1174
|
+
:data-business-gap-reason="nestedBlockNeedsHumanIntervention(nestedBlock) ? nestedBlockBusinessGapReason(nestedBlock) : undefined"
|
|
1175
|
+
:data-business-gap-diagnostics="nestedBlockNeedsHumanIntervention(nestedBlock) ? nestedBlockFailureReason(nestedBlock) : undefined"
|
|
1176
|
+
:style="referenceCompositeDiagnosticStyle('', nestedBlock, index, customCanvasVisibleNestedBlocks(effectiveData as CustomCanvasData))"
|
|
1177
|
+
aria-hidden="true"
|
|
1178
|
+
/>
|
|
1179
|
+
</div>
|
|
1180
|
+
<div
|
|
1181
|
+
v-else-if="customCanvasAlertLeafContainer(effectiveBlock, effectiveData as CustomCanvasData)"
|
|
1182
|
+
class="workbench-image-alert-ranking-list flex h-full min-h-0 w-full flex-col overflow-hidden rounded-md bg-[#241817] px-5 py-3 text-[#f8efe9]"
|
|
1183
|
+
>
|
|
1184
|
+
<div class="mb-1 flex h-6 shrink-0 items-center justify-between gap-2 pr-2">
|
|
1185
|
+
<span class="truncate text-base font-semibold leading-5 text-[#fff7ed]" :title="effectiveBlock.title">{{ effectiveBlock.title }}</span>
|
|
1186
|
+
<span class="rounded-full bg-red-600 px-2.5 py-1 text-xs font-semibold leading-none text-white">P1</span>
|
|
1187
|
+
</div>
|
|
1188
|
+
<div class="grid min-h-0 flex-1 gap-1 overflow-hidden" style="grid-template-rows: repeat(3, minmax(28px, 1fr));">
|
|
1189
|
+
<div
|
|
1190
|
+
v-for="(item, index) in customCanvasAlertLeafItems(effectiveData as CustomCanvasData).slice(0, 3)"
|
|
1191
|
+
:key="`custom-alert-${index}-${imageComposeAlertRankingTitle(item, index)}`"
|
|
1192
|
+
class="workbench-image-alert-ranking-row grid min-h-0 items-center overflow-hidden rounded-md bg-transparent text-sm"
|
|
1193
|
+
>
|
|
1194
|
+
<span :class="['workbench-image-alert-ranking-severity', ...imageComposeAlertSeverityClasses(item)]">{{ imageComposeAlertRankingSeverity(item) }}</span>
|
|
1195
|
+
<strong class="workbench-image-alert-ranking-title min-w-0 truncate text-sm text-[#f8efe9]" :title="imageComposeAlertRankingTitle(item, index)">{{ imageComposeAlertRankingTitle(item, index) }}</strong>
|
|
1196
|
+
<time class="workbench-image-alert-ranking-time shrink-0 text-sm text-[#d7c0ba]" :title="imageComposeAlertRankingTime(item, index)">{{ imageComposeAlertRankingTime(item, index) }}</time>
|
|
1197
|
+
</div>
|
|
1198
|
+
</div>
|
|
1199
|
+
</div>
|
|
1200
|
+
<div
|
|
1201
|
+
v-else-if="customCanvasUsesReferenceCompositePreview(effectiveBlock, effectiveData as CustomCanvasData)"
|
|
1202
|
+
:class="customCanvasNestedBlockContainerClasses(effectiveBlock, effectiveData as CustomCanvasData)"
|
|
1203
|
+
>
|
|
1204
|
+
<span
|
|
1205
|
+
v-for="(nestedBlock, index) in customCanvasVisibleNestedBlocks(effectiveData as CustomCanvasData)"
|
|
1206
|
+
:key="`diagnostic-${nestedBlock.id}`"
|
|
1207
|
+
data-testid="workbench-nested-card-preview"
|
|
1208
|
+
:data-parent-block-id="effectiveBlock.id"
|
|
1209
|
+
:data-nested-block-id="nestedBlock.id"
|
|
1210
|
+
:data-nested-card-id="nestedBlock.id"
|
|
1211
|
+
:data-nested-card-title="nestedBlock.title"
|
|
1212
|
+
:data-nested-card-kind="nestedBlock.kind"
|
|
1213
|
+
:data-capability-id="nestedBlock.capabilityId"
|
|
1214
|
+
:data-compose-source="nestedBlockComposeSource(nestedBlock)"
|
|
1215
|
+
:data-binding-id="nestedBlock.dataBindingId || nestedBlock.dataBinding?.bindingId || nestedBlock.dataBinding?.id || ''"
|
|
1216
|
+
:data-binding-status="nestedBlock.dataBindingStatus"
|
|
1217
|
+
:data-renderer-key="nestedBlockRendererKey(nestedBlock)"
|
|
1218
|
+
:data-data-shape="nestedBlock.dataShape"
|
|
1219
|
+
:data-visual-kind="nestedBlockVisualKind(nestedBlock)"
|
|
1220
|
+
:data-business-gap="nestedBlockNeedsHumanIntervention(nestedBlock) ? 'true' : undefined"
|
|
1221
|
+
:data-business-gap-reason="nestedBlockNeedsHumanIntervention(nestedBlock) ? nestedBlockBusinessGapReason(nestedBlock) : undefined"
|
|
1222
|
+
:data-business-gap-diagnostics="nestedBlockNeedsHumanIntervention(nestedBlock) ? nestedBlockFailureReason(nestedBlock) : undefined"
|
|
1223
|
+
:style="referenceCompositeDiagnosticStyle(customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData), nestedBlock, index, customCanvasVisibleNestedBlocks(effectiveData as CustomCanvasData))"
|
|
1224
|
+
aria-hidden="true"
|
|
1225
|
+
/>
|
|
1226
|
+
<div v-if="customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData) !== 'riskSummary'" class="workbench-reference-panel-header grid h-[30px] shrink-0 grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-2 overflow-hidden px-2 text-slate-900">
|
|
1227
|
+
<i class="h-2.5 w-2.5 rounded-full bg-[#d83a3a]" />
|
|
1228
|
+
<h3 class="truncate text-sm font-semibold leading-5" :title="effectiveBlock.title">{{ effectiveBlock.title }}</h3>
|
|
1229
|
+
<span class="max-w-[8rem] truncate rounded-full border border-slate-200 bg-slate-50 px-1.5 py-0.5 text-xs font-semibold leading-4 text-slate-500" :title="referenceCompositeHeaderChip(customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData))">
|
|
1230
|
+
{{ referenceCompositeHeaderChip(customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData)) }}
|
|
1231
|
+
</span>
|
|
1232
|
+
</div>
|
|
1233
|
+
<div
|
|
1234
|
+
v-if="customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData) === 'riskSummary'"
|
|
1235
|
+
class="workbench-reference-risk-summary-band grid min-h-0 flex-1 grid-cols-[1.42fr_repeat(4,minmax(0,0.86fr))_2.18fr] items-stretch gap-1.5 overflow-hidden rounded-md bg-[#172235] p-2 text-white"
|
|
1236
|
+
>
|
|
1237
|
+
<section class="workbench-reference-risk-summary-body grid min-h-0 grid-cols-[4.75rem_minmax(0,1fr)] items-center gap-2 overflow-hidden">
|
|
1238
|
+
<div class="workbench-reference-risk-score-donut grid h-[4.5rem] w-[4.5rem] place-items-center rounded-full bg-[conic-gradient(#dc2f2f_0_62%,#66758a_62%_100%)] p-2">
|
|
1239
|
+
<div class="grid h-full w-full place-items-center rounded-full bg-white text-base font-bold leading-none text-[#0b1f3a]">{{ referenceRiskMetricValue(effectiveData as CustomCanvasData, /经营健康|综合得分|health|score/i, '62 分') }}</div>
|
|
1240
|
+
</div>
|
|
1241
|
+
<div class="min-w-0">
|
|
1242
|
+
<div class="truncate text-xs font-semibold uppercase tracking-[0.04em] text-slate-300">GLOBAL RISK POSTURE</div>
|
|
1243
|
+
<h4 class="mt-0.5 truncate text-sm font-semibold leading-5 text-white" title="集团经营健康综合得分">集团经营健康综合得分</h4>
|
|
1244
|
+
<p class="workbench-reference-risk-narrative max-h-9 overflow-hidden text-xs leading-[18px] text-slate-200" title="低于安全线,盈利、资金、投资项目三类风险同步抬升。">低于安全线,盈利、资金、投资项目三类风险同步抬升。</p>
|
|
1245
|
+
</div>
|
|
1246
|
+
</section>
|
|
1247
|
+
<section
|
|
1248
|
+
v-for="item in referenceRiskKpiItems(effectiveData as CustomCanvasData)"
|
|
1249
|
+
:key="`risk-kpi-${item.label}`"
|
|
1250
|
+
class="workbench-reference-risk-kpi-tile grid min-h-0 grid-rows-[auto_auto_minmax(0,1fr)] overflow-hidden rounded-md border px-2 py-1.5"
|
|
1251
|
+
:class="item.tone === 'warning' ? 'border-amber-500/40 bg-amber-500/15' : 'border-red-500/40 bg-red-500/15'"
|
|
1252
|
+
>
|
|
1253
|
+
<div class="truncate text-xs font-semibold leading-4 text-slate-100" :title="item.label">{{ item.label }}</div>
|
|
1254
|
+
<div class="truncate pt-2 text-2xl font-bold leading-none text-white" :title="item.value">{{ item.value }}</div>
|
|
1255
|
+
<div class="self-end truncate text-xs leading-4 text-slate-300" :title="item.detail">{{ item.detail }}</div>
|
|
1256
|
+
</section>
|
|
1257
|
+
<section class="grid min-h-0 grid-rows-[auto_minmax(0,1fr)_auto] gap-1 overflow-hidden rounded-md border border-white/10 bg-white/8 px-2 py-1.5">
|
|
1258
|
+
<h4 class="truncate text-xs font-semibold uppercase tracking-[0.12em] text-slate-200">TODAY MOVEMENT</h4>
|
|
1259
|
+
<div class="grid min-h-0 gap-0.5 overflow-hidden" style="grid-auto-rows: minmax(0, 1fr);">
|
|
1260
|
+
<div v-for="(item, index) in referenceRiskMovementItems(effectiveData as CustomCanvasData)" :key="`risk-move-${index}`" class="grid min-h-0 grid-cols-[auto_minmax(0,1fr)] items-center gap-1.5 overflow-hidden rounded bg-white/8 px-1.5 py-0.5 text-xs">
|
|
1261
|
+
<i class="h-1.5 w-1.5 rounded-full bg-red-400" />
|
|
1262
|
+
<span class="truncate font-semibold leading-4 text-slate-100" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1263
|
+
</div>
|
|
1264
|
+
</div>
|
|
1265
|
+
<div class="workbench-reference-risk-movement-action grid h-6 grid-cols-[auto_minmax(0,1fr)] items-center gap-1.5 rounded border border-white/15 bg-white/8 px-1.5 text-xs font-semibold text-slate-100">
|
|
1266
|
+
<span class="text-sm leading-none">⌄</span>
|
|
1267
|
+
<span class="truncate text-right leading-4">一键风险全景下钻</span>
|
|
1268
|
+
</div>
|
|
1269
|
+
</section>
|
|
1270
|
+
</div>
|
|
1271
|
+
<div
|
|
1272
|
+
v-else-if="customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData) === 'quickWorkbench'"
|
|
1273
|
+
class="workbench-reference-quick-workbench-panel grid min-h-0 flex-1 grid-rows-[1fr_1fr_1.05fr_1fr] gap-2 overflow-hidden px-3 pb-3"
|
|
1274
|
+
>
|
|
1275
|
+
<section
|
|
1276
|
+
v-for="group in referenceQuickWorkbenchGroups()"
|
|
1277
|
+
:key="`quick-workbench-${group.id}`"
|
|
1278
|
+
class="grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-md border border-slate-200 bg-slate-50 px-3 py-2"
|
|
1279
|
+
>
|
|
1280
|
+
<div class="grid h-6 grid-cols-[minmax(0,1fr)_auto] items-center gap-2">
|
|
1281
|
+
<h4 class="truncate text-sm font-semibold leading-5 text-slate-900" :title="group.title">{{ group.title }}</h4>
|
|
1282
|
+
<span v-if="group.id === 'todo'" class="inline-flex h-6 max-w-[4.5rem] shrink-0 items-center justify-center truncate rounded-full bg-red-50 px-2 text-xs font-semibold leading-none text-red-600" :title="referenceQuickWorkbenchUrgentBadge(effectiveData as CustomCanvasData)">{{ referenceQuickWorkbenchUrgentBadge(effectiveData as CustomCanvasData) }}</span>
|
|
1283
|
+
</div>
|
|
1284
|
+
<div
|
|
1285
|
+
v-if="group.id === 'entry'"
|
|
1286
|
+
class="mt-2 grid min-h-0 grid-cols-2 gap-1.5 overflow-hidden"
|
|
1287
|
+
>
|
|
1288
|
+
<div
|
|
1289
|
+
v-for="(item, index) in referenceQuickWorkbenchGroupItems(effectiveData as CustomCanvasData, group)"
|
|
1290
|
+
:key="`quick-entry-${index}`"
|
|
1291
|
+
class="grid min-h-0 place-items-center overflow-hidden rounded border border-[#b8c9f8] bg-[#eef4ff] px-2 text-center text-sm font-semibold leading-5 text-[#1f55b8]"
|
|
1292
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1293
|
+
>
|
|
1294
|
+
<span class="max-w-full truncate">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1295
|
+
</div>
|
|
1296
|
+
</div>
|
|
1297
|
+
<div v-else class="mt-2 grid min-h-0 gap-1 overflow-hidden" style="grid-auto-rows: minmax(0, 1fr);">
|
|
1298
|
+
<div
|
|
1299
|
+
v-for="(item, index) in referenceQuickWorkbenchGroupItems(effectiveData as CustomCanvasData, group)"
|
|
1300
|
+
:key="`quick-row-${group.id}-${index}`"
|
|
1301
|
+
class="grid min-h-0 grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-2 overflow-hidden text-sm leading-5"
|
|
1302
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1303
|
+
>
|
|
1304
|
+
<i :class="nestedBlockDotClasses(item)" />
|
|
1305
|
+
<span class="min-w-0 truncate text-slate-600">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1306
|
+
<b class="max-w-[4rem] truncate text-right text-slate-900" :title="nestedBlockItemValue(item)">{{ nestedBlockItemValue(item) }}</b>
|
|
1307
|
+
</div>
|
|
1308
|
+
</div>
|
|
1309
|
+
</section>
|
|
1310
|
+
</div>
|
|
1311
|
+
<div
|
|
1312
|
+
v-else-if="customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData) === 'strategyKpi'"
|
|
1313
|
+
class="workbench-reference-strategy-kpi-panel grid min-h-0 flex-1 grid-cols-[1.22fr_repeat(3,minmax(0,1fr))] grid-rows-[minmax(0,1fr)_minmax(0,1fr)_auto] gap-2 overflow-hidden px-3 pb-3"
|
|
1314
|
+
>
|
|
1315
|
+
<button
|
|
1316
|
+
v-for="item in referenceStrategyKpiMetrics(effectiveData as CustomCanvasData).slice(0, 1)"
|
|
1317
|
+
:key="`strategy-kpi-primary-${nestedBlockItemLabel(item, 0)}`"
|
|
1318
|
+
type="button"
|
|
1319
|
+
class="workbench-reference-strategy-kpi-main relative row-span-2 grid min-h-0 overflow-hidden rounded-md bg-[#1769d6] p-3 text-left text-white transition hover:ring-2 hover:ring-[#4C78FC]/35 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-offset-2 focus-visible:ring-offset-[#1769d6]"
|
|
1320
|
+
v-bind="referenceItemNestedCardAttrs(item)"
|
|
1321
|
+
:title="nestedBlockItemTitle(item, 0)"
|
|
1322
|
+
:aria-label="nestedBlockItemTitle(item, 0)"
|
|
1323
|
+
:tabindex="referenceItemNestedRoleLabel(item) ? 0 : -1"
|
|
1324
|
+
@pointerdown.stop
|
|
1325
|
+
@click.stop="focusReferenceNestedItem(item)"
|
|
1326
|
+
>
|
|
1327
|
+
<div class="relative z-10 min-w-0">
|
|
1328
|
+
<div class="grid grid-cols-[minmax(0,1fr)_auto] items-start gap-2">
|
|
1329
|
+
<div class="truncate text-sm font-semibold leading-5 text-blue-100" :title="nestedBlockItemLabel(item, 0)">{{ nestedBlockItemLabel(item, 0) }}</div>
|
|
1330
|
+
<span v-if="referenceItemNestedRoleLabel(item)" class="workbench-nested-card-role-badge shrink-0 rounded border border-white/30 bg-white/15 px-1.5 py-0 text-[12px] font-semibold leading-4 text-blue-50">{{ referenceItemNestedRoleLabel(item) }}</span>
|
|
1331
|
+
</div>
|
|
1332
|
+
<strong class="mt-3 block max-w-full truncate text-[clamp(2rem,4.3vw,3.4rem)] font-bold leading-none" :title="nestedBlockItemValue(item)">{{ nestedBlockItemValue(item) }}</strong>
|
|
1333
|
+
<p class="mt-2 truncate text-sm font-semibold leading-5 text-blue-50" :title="nestedBlockItemDetail(item)">{{ nestedBlockItemDetail(item) }}</p>
|
|
1334
|
+
</div>
|
|
1335
|
+
<svg class="absolute inset-x-4 bottom-4 h-[38%] text-white/80" viewBox="0 0 200 76" preserveAspectRatio="none" aria-hidden="true">
|
|
1336
|
+
<path d="M0 68 H200" stroke="rgba(255,255,255,0.24)" stroke-width="2" />
|
|
1337
|
+
<path :d="referenceStrategyKpiTrendPath(effectiveData as CustomCanvasData)" fill="none" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" />
|
|
1338
|
+
</svg>
|
|
1339
|
+
<div class="absolute -bottom-12 right-[-24px] h-40 w-40 rounded-full border-[22px] border-white/25" aria-hidden="true" />
|
|
1340
|
+
</button>
|
|
1341
|
+
<button
|
|
1342
|
+
v-for="(item, index) in referenceStrategyKpiMetrics(effectiveData as CustomCanvasData).slice(1)"
|
|
1343
|
+
:key="`strategy-kpi-${index}`"
|
|
1344
|
+
type="button"
|
|
1345
|
+
class="grid min-h-0 grid-rows-[auto_minmax(1.75rem,1fr)_auto] overflow-hidden rounded-md border border-slate-200 bg-slate-50 px-3 py-2 text-left transition hover:border-[#4C78FC] hover:bg-[#f8fbff] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#4C78FC] focus-visible:ring-offset-2"
|
|
1346
|
+
v-bind="referenceItemNestedCardAttrs(item)"
|
|
1347
|
+
:title="nestedBlockItemTitle(item, index + 1)"
|
|
1348
|
+
:aria-label="nestedBlockItemTitle(item, index + 1)"
|
|
1349
|
+
:tabindex="referenceItemNestedRoleLabel(item) ? 0 : -1"
|
|
1350
|
+
@pointerdown.stop
|
|
1351
|
+
@click.stop="focusReferenceNestedItem(item)"
|
|
1352
|
+
>
|
|
1353
|
+
<div class="grid grid-cols-[minmax(0,1fr)_auto] items-center gap-2 text-sm leading-5">
|
|
1354
|
+
<span class="truncate text-slate-500" :title="nestedBlockItemLabel(item, index + 1)">{{ nestedBlockItemLabel(item, index + 1) }}</span>
|
|
1355
|
+
<span v-if="referenceItemNestedRoleLabel(item)" class="workbench-nested-card-role-badge shrink-0 rounded border border-slate-200 bg-white px-1.5 py-0 text-[12px] font-semibold leading-4 text-slate-500">{{ referenceItemNestedRoleLabel(item) }}</span>
|
|
1356
|
+
<span v-else :class="nestedBlockPillClasses(item)" :title="nestedBlockItemValue(item)">{{ nestedBlockToneClass(item) === 'critical' ? '紧张' : nestedBlockToneClass(item) === 'warning' ? '进行中' : '领先' }}</span>
|
|
1357
|
+
</div>
|
|
1358
|
+
<strong class="self-center truncate text-[clamp(1.15rem,1.55vw,1.65rem)] font-bold leading-none text-slate-900" :title="nestedBlockItemValue(item)">{{ nestedBlockItemValue(item) }}</strong>
|
|
1359
|
+
<div class="grid grid-cols-[minmax(0,1fr)_auto] items-center gap-2 text-xs leading-5 text-slate-500">
|
|
1360
|
+
<span class="h-2 overflow-hidden rounded-full bg-slate-200"><i :class="nestedBlockBarClasses(item)" :style="nestedBlockBarStyle(item, index === 0 ? 78 : 58)" /></span>
|
|
1361
|
+
<span class="max-w-[5rem] truncate text-right" :title="nestedBlockItemDetail(item)">{{ nestedBlockItemDetail(item) }}</span>
|
|
1362
|
+
</div>
|
|
1363
|
+
</button>
|
|
1364
|
+
<section class="workbench-reference-strategy-kpi-risk-strip col-span-4 grid min-h-[4.75rem] grid-cols-[minmax(4.75rem,auto)_minmax(0,1fr)] items-center gap-3 overflow-hidden rounded-md border border-red-200 bg-red-50 px-4 py-2">
|
|
1365
|
+
<strong class="truncate text-lg leading-6 text-red-600">{{ referenceStrategyKpiRiskSummaryLabel(effectiveData as CustomCanvasData) }}</strong>
|
|
1366
|
+
<div class="grid min-w-0 gap-3 overflow-hidden" :style="referenceStrategyKpiRiskItemsGridStyle(effectiveData as CustomCanvasData)">
|
|
1367
|
+
<button
|
|
1368
|
+
v-for="(item, index) in referenceStrategyKpiRiskItems(effectiveData as CustomCanvasData)"
|
|
1369
|
+
:key="`strategy-risk-${index}`"
|
|
1370
|
+
type="button"
|
|
1371
|
+
class="grid min-w-0 grid-rows-[auto_auto_auto] border-l border-red-200 bg-transparent pl-3 text-left text-xs leading-5 transition hover:text-[#4C78FC] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#4C78FC] focus-visible:ring-offset-2 first:border-l-0 first:pl-0"
|
|
1372
|
+
v-bind="referenceItemNestedCardAttrs(item)"
|
|
1373
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1374
|
+
:aria-label="nestedBlockItemTitle(item, index)"
|
|
1375
|
+
:tabindex="referenceItemNestedRoleLabel(item) ? 0 : -1"
|
|
1376
|
+
@pointerdown.stop
|
|
1377
|
+
@click.stop="focusReferenceNestedItem(item)"
|
|
1378
|
+
>
|
|
1379
|
+
<b class="truncate text-sm leading-5 text-slate-700">{{ nestedBlockItemLabel(item, index) }}</b>
|
|
1380
|
+
<span class="truncate text-slate-600">{{ nestedBlockItemDetail(item) || nestedBlockItemValue(item) }}</span>
|
|
1381
|
+
<span v-if="referenceItemNestedRoleLabel(item)" class="workbench-nested-card-role-badge mt-0.5 w-fit max-w-full truncate rounded border border-red-200 bg-white px-1.5 py-0 text-[12px] font-semibold leading-4 text-red-500">{{ referenceItemNestedRoleLabel(item) }}</span>
|
|
1382
|
+
</button>
|
|
1383
|
+
</div>
|
|
1384
|
+
</section>
|
|
1385
|
+
</div>
|
|
1386
|
+
<div
|
|
1387
|
+
v-else-if="customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData) === 'operationHealth'"
|
|
1388
|
+
class="workbench-reference-operation-health-panel grid min-h-0 flex-1 grid-cols-[0.8fr_1.52fr_1.08fr] gap-2 overflow-hidden px-3 pb-3"
|
|
1389
|
+
>
|
|
1390
|
+
<section class="grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-md border border-slate-200 bg-slate-50 px-2 py-2">
|
|
1391
|
+
<h4 class="truncate text-sm font-semibold leading-5 text-slate-900">目标进度条</h4>
|
|
1392
|
+
<div class="mt-2 grid min-h-0 gap-1.5 overflow-hidden" style="grid-auto-rows: minmax(0, 1fr);">
|
|
1393
|
+
<div
|
|
1394
|
+
v-for="(item, index) in referenceOperationHealthProgressItems(effectiveData as CustomCanvasData)"
|
|
1395
|
+
:key="`operation-health-progress-${index}`"
|
|
1396
|
+
class="grid min-h-0 grid-rows-[auto_auto] gap-1 overflow-hidden text-xs leading-4"
|
|
1397
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1398
|
+
>
|
|
1399
|
+
<div class="grid grid-cols-[minmax(0,1fr)_auto] gap-2">
|
|
1400
|
+
<span class="min-w-0 truncate font-semibold text-slate-700">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1401
|
+
<b class="max-w-[4rem] truncate text-right text-slate-900">{{ nestedBlockItemValue(item) || '--' }}</b>
|
|
1402
|
+
</div>
|
|
1403
|
+
<span class="h-2 overflow-hidden rounded-full bg-slate-200"><i :class="nestedBlockBarClasses(item)" :style="nestedBlockBarStyle(item, 62)" /></span>
|
|
1404
|
+
</div>
|
|
1405
|
+
</div>
|
|
1406
|
+
</section>
|
|
1407
|
+
<section class="grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-md border border-slate-200 bg-white px-2 py-2">
|
|
1408
|
+
<h4 class="truncate text-sm font-semibold leading-5 text-slate-900">近6个月核心指标</h4>
|
|
1409
|
+
<div class="mt-2 grid min-h-0 grid-cols-6 items-end gap-1.5 overflow-hidden border-b border-slate-200 px-1 pb-1.5">
|
|
1410
|
+
<div
|
|
1411
|
+
v-for="(item, index) in referenceOperationHealthTrendItems(effectiveData as CustomCanvasData)"
|
|
1412
|
+
:key="`operation-health-trend-${index}`"
|
|
1413
|
+
class="grid h-full min-h-0 grid-rows-[minmax(0,1fr)_auto] items-end gap-1 text-center text-xs text-slate-500"
|
|
1414
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1415
|
+
>
|
|
1416
|
+
<span class="flex h-full items-end justify-center"><i :class="referenceOpsTrendBarClasses(item)" :style="{ height: nestedBlockItemProgress(item, 54), width: '100%' }" /></span>
|
|
1417
|
+
<span class="truncate">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1418
|
+
</div>
|
|
1419
|
+
</div>
|
|
1420
|
+
</section>
|
|
1421
|
+
<section class="grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-md border border-slate-200 bg-slate-50 px-2 py-2">
|
|
1422
|
+
<h4 class="truncate text-sm font-semibold leading-5 text-slate-900">结构占比</h4>
|
|
1423
|
+
<div class="mt-2 grid min-h-0 grid-cols-[4.75rem_minmax(0,1fr)] items-center gap-2 overflow-hidden">
|
|
1424
|
+
<div class="grid h-[4.5rem] w-[4.5rem] place-items-center rounded-full text-xs font-semibold text-slate-500" :style="nestedBlockDonutStyle(referenceOperationHealthStructureBlock(effectiveData as CustomCanvasData))">结构</div>
|
|
1425
|
+
<div class="grid min-w-0 gap-1 overflow-hidden text-xs leading-4">
|
|
1426
|
+
<div
|
|
1427
|
+
v-for="(item, index) in referenceOperationHealthStructureItems(effectiveData as CustomCanvasData)"
|
|
1428
|
+
:key="`operation-health-structure-${index}`"
|
|
1429
|
+
class="grid grid-cols-[minmax(0,1fr)_auto] gap-1 overflow-hidden"
|
|
1430
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1431
|
+
>
|
|
1432
|
+
<span class="truncate text-slate-600">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1433
|
+
<b class="max-w-[3.5rem] truncate text-slate-900">{{ nestedBlockItemValue(item) || '--' }}</b>
|
|
1434
|
+
</div>
|
|
1435
|
+
</div>
|
|
1436
|
+
</div>
|
|
1437
|
+
</section>
|
|
1438
|
+
</div>
|
|
1439
|
+
<div
|
|
1440
|
+
v-else-if="customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData) === 'operationEfficiency'"
|
|
1441
|
+
class="workbench-reference-operation-efficiency-panel grid min-h-0 flex-1 gap-2 overflow-hidden px-3 pb-3"
|
|
1442
|
+
:style="referenceOperationEfficiencyPanelStyle(effectiveData as CustomCanvasData)"
|
|
1443
|
+
>
|
|
1444
|
+
<section
|
|
1445
|
+
v-for="group in referenceOperationEfficiencyGroups(effectiveData as CustomCanvasData)"
|
|
1446
|
+
:key="`operation-efficiency-${group.id}`"
|
|
1447
|
+
class="grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-md border border-slate-200 bg-slate-50 px-2 py-2"
|
|
1448
|
+
>
|
|
1449
|
+
<div class="grid h-6 grid-cols-[minmax(0,1fr)_auto] items-center gap-2">
|
|
1450
|
+
<h4 class="truncate text-sm font-semibold leading-5 text-slate-900" :title="group.title">{{ group.title }}</h4>
|
|
1451
|
+
<span class="rounded-full border border-slate-200 bg-white px-1.5 py-0.5 text-xs font-semibold leading-none text-slate-500">{{ group.items.length }}</span>
|
|
1452
|
+
</div>
|
|
1453
|
+
<div
|
|
1454
|
+
:class="[
|
|
1455
|
+
'mt-2 grid min-h-0 gap-1 overflow-hidden',
|
|
1456
|
+
group.items.length <= 1 ? 'h-full' : 'h-full auto-rows-fr',
|
|
1457
|
+
]"
|
|
1458
|
+
>
|
|
1459
|
+
<button
|
|
1460
|
+
v-for="(item, index) in group.items.slice(0, 4)"
|
|
1461
|
+
:key="`operation-efficiency-row-${group.id}-${index}`"
|
|
1462
|
+
type="button"
|
|
1463
|
+
:class="[
|
|
1464
|
+
'overflow-hidden rounded border border-slate-100 bg-white text-left text-xs leading-5 transition hover:border-[#4C78FC] hover:bg-[#f8fbff] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#4C78FC] focus-visible:ring-offset-2',
|
|
1465
|
+
group.items.length <= 1
|
|
1466
|
+
? 'workbench-reference-operation-efficiency-single grid h-full min-h-0 grid-rows-[auto_minmax(0,1fr)_auto] gap-2 px-3 py-2'
|
|
1467
|
+
: 'grid min-h-0 grid-cols-[minmax(0,1fr)_auto_auto] items-center gap-2 px-2 py-1',
|
|
1468
|
+
]"
|
|
1469
|
+
v-bind="referenceItemNestedCardAttrs(item)"
|
|
1470
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1471
|
+
:aria-label="nestedBlockItemTitle(item, index)"
|
|
1472
|
+
:tabindex="referenceItemNestedRoleLabel(item) ? 0 : -1"
|
|
1473
|
+
@pointerdown.stop
|
|
1474
|
+
@click.stop="focusReferenceNestedItem(item)"
|
|
1475
|
+
>
|
|
1476
|
+
<template v-if="group.items.length <= 1">
|
|
1477
|
+
<div class="grid min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-2">
|
|
1478
|
+
<span class="min-w-0 truncate font-semibold text-slate-700">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1479
|
+
<span v-if="referenceItemNestedRoleLabel(item)" class="workbench-nested-card-role-badge max-w-[5.5rem] shrink-0 truncate rounded border border-slate-200 bg-slate-50 px-1.5 py-0 text-[12px] font-semibold leading-4 text-slate-500">
|
|
1480
|
+
{{ referenceItemNestedRoleLabel(item) }}
|
|
1481
|
+
</span>
|
|
1482
|
+
</div>
|
|
1483
|
+
<strong :class="['self-center truncate text-[clamp(1.25rem,2vw,1.75rem)] font-bold leading-none', nestedBlockToneClass(item) === 'critical' ? 'text-red-600' : nestedBlockToneClass(item) === 'warning' ? 'text-amber-700' : 'text-slate-900']">
|
|
1484
|
+
{{ nestedBlockItemValue(item) || '--' }}
|
|
1485
|
+
</strong>
|
|
1486
|
+
<p class="min-w-0 truncate text-slate-500" :title="nestedBlockItemDetail(item)">{{ nestedBlockItemDetail(item) || '等待补充业务口径后问数' }}</p>
|
|
1487
|
+
</template>
|
|
1488
|
+
<template v-else>
|
|
1489
|
+
<span class="min-w-0 truncate font-semibold text-slate-700">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1490
|
+
<b :class="['max-w-[4.5rem] truncate text-right font-semibold', nestedBlockToneClass(item) === 'critical' ? 'text-red-600' : nestedBlockToneClass(item) === 'warning' ? 'text-amber-700' : 'text-slate-900']">
|
|
1491
|
+
{{ nestedBlockItemValue(item) || '--' }}
|
|
1492
|
+
</b>
|
|
1493
|
+
<span v-if="referenceItemNestedRoleLabel(item)" class="workbench-nested-card-role-badge max-w-[4.75rem] shrink-0 truncate rounded border border-slate-200 bg-slate-50 px-1.5 py-0 text-[12px] font-semibold leading-4 text-slate-500">
|
|
1494
|
+
{{ referenceItemNestedRoleLabel(item) }}
|
|
1495
|
+
</span>
|
|
1496
|
+
</template>
|
|
1497
|
+
</button>
|
|
1498
|
+
</div>
|
|
1499
|
+
</section>
|
|
1500
|
+
</div>
|
|
1501
|
+
<div
|
|
1502
|
+
v-else-if="customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData) === 'hrOrganization'"
|
|
1503
|
+
class="workbench-reference-hr-organization-panel grid min-h-0 flex-1 grid-cols-[0.82fr_1.18fr] grid-rows-[minmax(0,0.62fr)_minmax(0,0.38fr)] gap-2 overflow-hidden px-3 pb-3 text-xs leading-4"
|
|
1504
|
+
>
|
|
1505
|
+
<section class="row-span-2 grid min-h-0 content-start gap-1.5 overflow-hidden rounded-md border border-slate-200 bg-slate-50 px-2 py-2">
|
|
1506
|
+
<h4 class="truncate text-sm font-semibold leading-5 text-slate-900">组织结构概览</h4>
|
|
1507
|
+
<div
|
|
1508
|
+
v-for="(item, index) in referenceHrOrganizationMetrics(effectiveData as CustomCanvasData)"
|
|
1509
|
+
:key="`hr-org-metric-${index}`"
|
|
1510
|
+
class="grid min-h-[3.5rem] grid-cols-[minmax(0,1fr)_auto] items-center gap-2 overflow-hidden rounded border border-slate-100 bg-white px-2 py-1.5"
|
|
1511
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1512
|
+
>
|
|
1513
|
+
<span class="min-w-0 truncate font-semibold text-slate-600">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1514
|
+
<strong class="max-w-[5rem] truncate text-right text-base font-bold leading-5 text-slate-950" :title="nestedBlockItemValue(item)">{{ nestedBlockItemValue(item) || '--' }}</strong>
|
|
1515
|
+
</div>
|
|
1516
|
+
</section>
|
|
1517
|
+
<section class="grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-md border border-slate-200 bg-white px-2 py-2">
|
|
1518
|
+
<h4 class="truncate text-sm font-semibold leading-5 text-slate-900">部门编制达成</h4>
|
|
1519
|
+
<div class="mt-2 grid min-h-0 content-start gap-1.5 overflow-hidden">
|
|
1520
|
+
<div
|
|
1521
|
+
v-for="(item, index) in referenceHrOrganizationRows(effectiveData as CustomCanvasData)"
|
|
1522
|
+
:key="`hr-org-row-${index}`"
|
|
1523
|
+
class="grid grid-cols-[4.75rem_minmax(0,1fr)_3.5rem] items-center gap-2 overflow-hidden text-xs"
|
|
1524
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1525
|
+
>
|
|
1526
|
+
<span class="truncate font-semibold text-slate-700">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1527
|
+
<span class="h-2 overflow-hidden rounded-full bg-slate-200"><i :class="nestedBlockBarClasses(item)" :style="nestedBlockBarStyle(item, 68)" /></span>
|
|
1528
|
+
<b class="truncate text-right text-slate-800">{{ nestedBlockItemValue(item) || nestedBlockItemProgress(item, 68) }}</b>
|
|
1529
|
+
</div>
|
|
1530
|
+
</div>
|
|
1531
|
+
</section>
|
|
1532
|
+
<section class="grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-md border border-slate-200 bg-slate-50 px-2 py-2">
|
|
1533
|
+
<h4 class="truncate text-sm font-semibold leading-5 text-slate-900">关键异动趋势</h4>
|
|
1534
|
+
<div class="mt-2 grid min-h-0 grid-cols-6 items-end gap-1.5 overflow-hidden border-b border-slate-200 px-1 pb-1.5">
|
|
1535
|
+
<div
|
|
1536
|
+
v-for="(item, index) in referenceHrCostTrendItems(effectiveData as CustomCanvasData).slice(0, 6)"
|
|
1537
|
+
:key="`hr-org-trend-${index}`"
|
|
1538
|
+
class="grid h-full min-h-0 grid-rows-[minmax(0,1fr)_auto] items-end gap-1 text-center"
|
|
1539
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1540
|
+
>
|
|
1541
|
+
<span class="flex h-full min-h-0 items-end justify-center"><i :class="referenceOpsTrendBarClasses(item)" :style="{ height: nestedBlockItemProgress(item, 58), width: '62%' }" /></span>
|
|
1542
|
+
<span class="truncate text-slate-500">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1543
|
+
</div>
|
|
1544
|
+
</div>
|
|
1545
|
+
</section>
|
|
1546
|
+
</div>
|
|
1547
|
+
<div
|
|
1548
|
+
v-else-if="customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData) === 'hrRiskCompliance'"
|
|
1549
|
+
class="workbench-reference-hr-risk-panel grid min-h-0 flex-1 grid-cols-3 grid-rows-[minmax(0,0.42fr)_minmax(0,0.58fr)] gap-2 overflow-hidden px-3 pb-3 text-xs leading-4"
|
|
1550
|
+
>
|
|
1551
|
+
<section
|
|
1552
|
+
v-for="(item, index) in referenceHrRiskRows(effectiveData as CustomCanvasData).slice(0, 3)"
|
|
1553
|
+
:key="`hr-risk-kpi-${index}`"
|
|
1554
|
+
:class="['grid min-h-0 grid-rows-[auto_minmax(0,1fr)_auto] overflow-hidden rounded-md border px-2 py-2', nestedBlockToneClass(item) === 'critical' ? 'border-red-100 bg-red-50' : 'border-amber-100 bg-amber-50']"
|
|
1555
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1556
|
+
>
|
|
1557
|
+
<span class="truncate font-semibold text-slate-700">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1558
|
+
<strong :class="['self-center truncate text-[clamp(1.35rem,2.2vw,1.9rem)] font-bold leading-none', nestedBlockToneClass(item) === 'critical' ? 'text-red-700' : 'text-amber-800']">{{ nestedBlockItemValue(item) || '--' }}</strong>
|
|
1559
|
+
<span class="truncate text-slate-600">{{ nestedBlockItemDetail(item) || '待 HRBP 跟进' }}</span>
|
|
1560
|
+
</section>
|
|
1561
|
+
<section class="col-span-3 grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-md border border-slate-200 bg-white px-2 py-2">
|
|
1562
|
+
<h4 class="truncate text-sm font-semibold leading-5 text-slate-900">合规处置清单</h4>
|
|
1563
|
+
<div class="mt-2 grid min-h-0 content-start gap-1.5 overflow-hidden">
|
|
1564
|
+
<div
|
|
1565
|
+
v-for="(item, index) in referenceHrRiskRows(effectiveData as CustomCanvasData)"
|
|
1566
|
+
:key="`hr-risk-row-${index}`"
|
|
1567
|
+
class="grid min-h-[2.25rem] grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-2 overflow-hidden rounded border border-slate-100 bg-slate-50 px-2 py-1"
|
|
1568
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1569
|
+
>
|
|
1570
|
+
<i :class="nestedBlockDotClasses(item)" />
|
|
1571
|
+
<span class="min-w-0 truncate font-semibold text-slate-700">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1572
|
+
<span :class="nestedBlockPillClasses(item)" :title="nestedBlockItemValue(item) || nestedBlockItemDetail(item)">{{ nestedBlockItemValue(item) || nestedBlockItemDetail(item) || '待确认' }}</span>
|
|
1573
|
+
</div>
|
|
1574
|
+
</div>
|
|
1575
|
+
</section>
|
|
1576
|
+
</div>
|
|
1577
|
+
<div
|
|
1578
|
+
v-else-if="customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData) === 'hrPeopleCost'"
|
|
1579
|
+
class="workbench-reference-hr-people-cost-panel grid min-h-0 flex-1 grid-cols-[0.9fr_1.1fr] gap-2 overflow-hidden px-3 pb-3 text-xs leading-4"
|
|
1580
|
+
>
|
|
1581
|
+
<section class="grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-md border border-slate-200 bg-slate-50 px-2 py-2">
|
|
1582
|
+
<h4 class="truncate text-sm font-semibold leading-5 text-slate-900">薪酬成本结构</h4>
|
|
1583
|
+
<div class="mt-2 grid min-h-0 content-start gap-1.5 overflow-hidden">
|
|
1584
|
+
<div
|
|
1585
|
+
v-for="(item, index) in referenceHrPeopleCostItems(effectiveData as CustomCanvasData)"
|
|
1586
|
+
:key="`hr-cost-item-${index}`"
|
|
1587
|
+
class="grid min-h-[2.75rem] grid-cols-[minmax(0,1fr)_auto] items-center gap-2 overflow-hidden rounded border border-slate-100 bg-white px-2 py-1"
|
|
1588
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1589
|
+
>
|
|
1590
|
+
<span class="min-w-0 truncate font-semibold text-slate-600">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1591
|
+
<strong :class="['max-w-[5rem] truncate text-right text-base leading-5', nestedBlockToneClass(item) === 'critical' ? 'text-red-600' : nestedBlockToneClass(item) === 'warning' ? 'text-amber-700' : 'text-slate-950']">{{ nestedBlockItemValue(item) || '--' }}</strong>
|
|
1592
|
+
</div>
|
|
1593
|
+
</div>
|
|
1594
|
+
</section>
|
|
1595
|
+
<section class="grid min-h-0 grid-rows-[auto_minmax(0,1fr)_auto] overflow-hidden rounded-md border border-slate-200 bg-white px-2 py-2">
|
|
1596
|
+
<h4 class="truncate text-sm font-semibold leading-5 text-slate-900">成本趋势与人效</h4>
|
|
1597
|
+
<div class="mt-2 grid min-h-0 grid-cols-5 items-end gap-2 overflow-hidden border-b border-slate-200 px-1 pb-2">
|
|
1598
|
+
<div
|
|
1599
|
+
v-for="(item, index) in referenceHrCostTrendItems(effectiveData as CustomCanvasData)"
|
|
1600
|
+
:key="`hr-cost-trend-${index}`"
|
|
1601
|
+
class="grid h-full min-h-0 grid-rows-[minmax(0,1fr)_auto] items-end gap-1 text-center"
|
|
1602
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1603
|
+
>
|
|
1604
|
+
<span class="flex h-full min-h-0 items-end justify-center"><i :class="referenceOpsTrendBarClasses(item)" :style="{ height: nestedBlockItemProgress(item, 62), width: '58%' }" /></span>
|
|
1605
|
+
<span class="truncate text-slate-500">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1606
|
+
</div>
|
|
1607
|
+
</div>
|
|
1608
|
+
<div class="mt-2 grid shrink-0 grid-cols-2 gap-1.5 overflow-hidden">
|
|
1609
|
+
<div
|
|
1610
|
+
v-for="(item, index) in referenceHrPeopleCostItems(effectiveData as CustomCanvasData).slice(2, 4)"
|
|
1611
|
+
:key="`hr-cost-footer-${index}`"
|
|
1612
|
+
class="grid min-h-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-2 overflow-hidden rounded border border-slate-100 bg-slate-50 px-2 py-1"
|
|
1613
|
+
:title="nestedBlockItemTitle(item, index + 2)"
|
|
1614
|
+
>
|
|
1615
|
+
<span class="truncate font-semibold text-slate-600">{{ nestedBlockItemLabel(item, index + 2) }}</span>
|
|
1616
|
+
<span :class="nestedBlockPillClasses(item)" :title="nestedBlockItemValue(item)">{{ nestedBlockItemValue(item) || '待确认' }}</span>
|
|
1617
|
+
</div>
|
|
1618
|
+
</div>
|
|
1619
|
+
</section>
|
|
1620
|
+
</div>
|
|
1621
|
+
<div
|
|
1622
|
+
v-else-if="customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData) === 'hrTalentTodo'"
|
|
1623
|
+
class="workbench-reference-hr-talent-panel grid min-h-0 flex-1 grid-cols-[0.78fr_1.22fr] gap-2 overflow-hidden px-3 pb-3 text-xs leading-4"
|
|
1624
|
+
>
|
|
1625
|
+
<section class="grid min-h-0 content-start gap-1.5 overflow-hidden rounded-md border border-slate-200 bg-slate-50 px-2 py-2">
|
|
1626
|
+
<h4 class="truncate text-sm font-semibold leading-5 text-slate-900">人才梯队</h4>
|
|
1627
|
+
<div
|
|
1628
|
+
v-for="(item, index) in referenceHrTalentMetrics(effectiveData as CustomCanvasData)"
|
|
1629
|
+
:key="`hr-talent-metric-${index}`"
|
|
1630
|
+
class="grid min-h-[3.75rem] grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded border border-slate-100 bg-white px-2 py-1.5"
|
|
1631
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1632
|
+
>
|
|
1633
|
+
<span class="truncate font-semibold text-slate-500">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1634
|
+
<strong class="self-center truncate text-xl font-bold leading-none text-slate-950" :title="nestedBlockItemValue(item)">{{ nestedBlockItemValue(item) || '--' }}</strong>
|
|
1635
|
+
</div>
|
|
1636
|
+
</section>
|
|
1637
|
+
<section class="grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-md border border-slate-200 bg-white px-2 py-2">
|
|
1638
|
+
<h4 class="truncate text-sm font-semibold leading-5 text-slate-900">重大人事待办</h4>
|
|
1639
|
+
<div class="mt-2 grid min-h-0 content-start gap-1.5 overflow-hidden">
|
|
1640
|
+
<div
|
|
1641
|
+
v-for="(item, index) in referenceHrTalentTodoRows(effectiveData as CustomCanvasData)"
|
|
1642
|
+
:key="`hr-talent-todo-${index}`"
|
|
1643
|
+
class="grid min-h-[2.45rem] grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-2 overflow-hidden rounded border border-slate-100 bg-slate-50 px-2 py-1"
|
|
1644
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1645
|
+
>
|
|
1646
|
+
<i :class="nestedBlockDotClasses(item)" />
|
|
1647
|
+
<span class="min-w-0 truncate font-semibold text-slate-700">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1648
|
+
<span :class="nestedBlockPillClasses(item)" :title="nestedBlockItemValue(item) || nestedBlockItemDetail(item)">{{ nestedBlockItemValue(item) || nestedBlockItemDetail(item) || '待确认' }}</span>
|
|
1649
|
+
</div>
|
|
1650
|
+
</div>
|
|
1651
|
+
</section>
|
|
1652
|
+
</div>
|
|
1653
|
+
<div
|
|
1654
|
+
v-else-if="customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData) === 'bidCollaboration'"
|
|
1655
|
+
class="workbench-reference-bid-collaboration-panel grid min-h-0 flex-1 overflow-hidden rounded-lg bg-[#f6fafc] px-3 pb-3 text-xs leading-4"
|
|
1656
|
+
>
|
|
1657
|
+
<section
|
|
1658
|
+
class="workbench-reference-bid-hero grid min-h-0 grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-3 overflow-hidden rounded-t-lg px-4 py-3 text-white"
|
|
1659
|
+
:style="{ background: referenceBidHero(effectiveBlock, effectiveData as CustomCanvasData).accent }"
|
|
1660
|
+
>
|
|
1661
|
+
<div class="grid h-12 w-12 place-items-center rounded-lg border border-white/25 bg-white/10 text-2xl font-semibold">
|
|
1662
|
+
{{ referenceBidHero(effectiveBlock, effectiveData as CustomCanvasData).icon }}
|
|
1663
|
+
</div>
|
|
1664
|
+
<div class="min-w-0">
|
|
1665
|
+
<h3 class="truncate text-xl font-semibold leading-7" :title="referenceBidHero(effectiveBlock, effectiveData as CustomCanvasData).title">
|
|
1666
|
+
{{ referenceBidHero(effectiveBlock, effectiveData as CustomCanvasData).title }}
|
|
1667
|
+
</h3>
|
|
1668
|
+
<p class="mt-0.5 truncate text-sm leading-5 text-white/75" :title="referenceBidHero(effectiveBlock, effectiveData as CustomCanvasData).subtitle">
|
|
1669
|
+
{{ referenceBidHero(effectiveBlock, effectiveData as CustomCanvasData).subtitle }}
|
|
1670
|
+
</p>
|
|
1671
|
+
</div>
|
|
1672
|
+
<div class="flex max-w-[34rem] flex-wrap justify-end gap-2 overflow-hidden text-xs font-semibold leading-5 text-white/90">
|
|
1673
|
+
<span class="rounded-full border border-white/20 bg-white/10 px-2.5 py-0.5">期间:今日</span>
|
|
1674
|
+
<span class="rounded-full border border-white/20 bg-white/10 px-2.5 py-0.5">口径:{{ referenceBidHero(effectiveBlock, effectiveData as CustomCanvasData).route }}</span>
|
|
1675
|
+
<span class="rounded-full border border-white/20 bg-white/10 px-2.5 py-0.5">范围:{{ referenceBidHero(effectiveBlock, effectiveData as CustomCanvasData).scope }}</span>
|
|
1676
|
+
<span class="rounded-full border border-white/20 bg-white/10 px-2.5 py-0.5">刷新:{{ referenceBidHero(effectiveBlock, effectiveData as CustomCanvasData).refresh }}</span>
|
|
1677
|
+
</div>
|
|
1678
|
+
</section>
|
|
1679
|
+
|
|
1680
|
+
<section class="grid min-h-[3rem] grid-cols-[auto_minmax(0,1fr)] items-center gap-3 overflow-hidden border-x border-b border-slate-200 bg-white px-4 py-2">
|
|
1681
|
+
<span class="shrink-0 font-semibold text-slate-500">快速入口</span>
|
|
1682
|
+
<div class="flex min-w-0 flex-wrap gap-2 overflow-hidden">
|
|
1683
|
+
<span
|
|
1684
|
+
v-for="action in referenceBidQuickActions(effectiveData as CustomCanvasData)"
|
|
1685
|
+
:key="action"
|
|
1686
|
+
class="rounded-md border border-slate-200 bg-white px-3 py-1 text-xs font-semibold leading-5 text-slate-700"
|
|
1687
|
+
>
|
|
1688
|
+
{{ action }}
|
|
1689
|
+
</span>
|
|
1690
|
+
</div>
|
|
1691
|
+
</section>
|
|
1692
|
+
|
|
1693
|
+
<section class="grid min-h-[5.75rem] grid-cols-4 gap-2 overflow-hidden pt-2">
|
|
1694
|
+
<div
|
|
1695
|
+
v-for="(item, index) in referenceBidKpiItems(effectiveData as CustomCanvasData)"
|
|
1696
|
+
:key="`bid-kpi-${index}`"
|
|
1697
|
+
:class="['grid min-h-0 grid-rows-[auto_minmax(0,1fr)_auto] overflow-hidden rounded-md border px-3 py-2', nestedBlockToneClass(item) === 'critical' ? 'border-red-200 bg-red-50' : nestedBlockToneClass(item) === 'warning' ? 'border-amber-200 bg-amber-50' : nestedBlockToneClass(item) === 'healthy' ? 'border-emerald-200 bg-emerald-50' : 'border-slate-200 bg-white']"
|
|
1698
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1699
|
+
>
|
|
1700
|
+
<span class="truncate font-semibold text-slate-500">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1701
|
+
<strong class="self-center truncate text-2xl font-bold leading-7 text-slate-950" :title="referenceBidSanitizedMetricValue(item)">{{ referenceBidSanitizedMetricValue(item) }}</strong>
|
|
1702
|
+
<span class="truncate text-slate-500" :title="nestedBlockItemDetail(item)">{{ nestedBlockItemDetail(item) }}</span>
|
|
1703
|
+
</div>
|
|
1704
|
+
</section>
|
|
1705
|
+
|
|
1706
|
+
<section class="grid min-h-[8rem] grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-md border border-slate-200 bg-white">
|
|
1707
|
+
<div class="grid h-9 grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-2 border-b border-slate-200 px-3">
|
|
1708
|
+
<i class="h-4 w-1.5 rounded-full bg-emerald-600" />
|
|
1709
|
+
<h4 class="truncate text-sm font-semibold leading-5 text-slate-900">目标标案信息</h4>
|
|
1710
|
+
<span class="truncate text-xs font-semibold text-slate-500">客户 / 产品 / 时间 / 地点</span>
|
|
1711
|
+
</div>
|
|
1712
|
+
<div
|
|
1713
|
+
class="grid min-h-0 gap-2 overflow-hidden p-2"
|
|
1714
|
+
:style="imageComposeBidTargetInfoGridStyle(referenceBidInfoItems(effectiveData as CustomCanvasData).slice(0, 9).length)"
|
|
1715
|
+
>
|
|
1716
|
+
<div
|
|
1717
|
+
v-for="(item, index) in referenceBidInfoItems(effectiveData as CustomCanvasData).slice(0, 9)"
|
|
1718
|
+
:key="`bid-info-${index}`"
|
|
1719
|
+
:class="[imageComposeBidInfoTileClasses(referenceBidInfoItems(effectiveData as CustomCanvasData).slice(0, 9).length), nestedBlockToneClass(item) === 'warning' ? 'border-amber-200 bg-amber-50' : 'border-slate-200 bg-white']"
|
|
1720
|
+
:style="imageComposeBidInfoTilePlacementStyle(index, referenceBidInfoItems(effectiveData as CustomCanvasData).slice(0, 9).length)"
|
|
1721
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1722
|
+
>
|
|
1723
|
+
<span class="truncate font-semibold leading-4 text-slate-500">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1724
|
+
<b class="truncate text-base leading-6 text-slate-900" :title="referenceBidSanitizedMetricValue(item, nestedBlockItemDetail(item) || '--')">{{ referenceBidSanitizedMetricValue(item, nestedBlockItemDetail(item) || '--') }}</b>
|
|
1725
|
+
</div>
|
|
1726
|
+
</div>
|
|
1727
|
+
</section>
|
|
1728
|
+
|
|
1729
|
+
<section class="grid min-h-0 grid-cols-3 gap-2 overflow-hidden">
|
|
1730
|
+
<div
|
|
1731
|
+
v-for="(section, sectionIndex) in referenceBidTableBlocks(effectiveData as CustomCanvasData)"
|
|
1732
|
+
:key="`bid-table-${section.block.id}`"
|
|
1733
|
+
class="grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-md border border-slate-200 bg-white"
|
|
1734
|
+
>
|
|
1735
|
+
<div class="grid h-9 grid-cols-[auto_minmax(0,1fr)] items-center gap-2 border-b border-slate-200 px-3">
|
|
1736
|
+
<i class="h-4 w-1.5 rounded-full bg-emerald-600" />
|
|
1737
|
+
<h4 class="truncate text-sm font-semibold leading-5 text-slate-900" :title="section.block.title">{{ section.block.title }}</h4>
|
|
1738
|
+
</div>
|
|
1739
|
+
<div class="grid min-h-0 gap-1 overflow-hidden p-2" style="grid-auto-rows: minmax(0, 1fr);">
|
|
1740
|
+
<div
|
|
1741
|
+
v-for="(item, index) in section.rows"
|
|
1742
|
+
:key="`bid-table-${sectionIndex}-${index}`"
|
|
1743
|
+
:class="['grid min-h-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-2 overflow-hidden rounded border px-2 py-1', nestedBlockToneClass(item) === 'critical' ? 'border-red-100 bg-red-50' : nestedBlockToneClass(item) === 'warning' ? 'border-amber-100 bg-amber-50' : nestedBlockToneClass(item) === 'healthy' ? 'border-emerald-100 bg-emerald-50' : 'border-slate-100 bg-slate-50']"
|
|
1744
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1745
|
+
>
|
|
1746
|
+
<span class="min-w-0 truncate font-semibold text-slate-700">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1747
|
+
<span :class="nestedBlockPillClasses(item)" :title="referenceBidSanitizedMetricValue(item, nestedBlockItemDetail(item) || '待确认')">{{ referenceBidSanitizedMetricValue(item, nestedBlockItemDetail(item) || '待确认') }}</span>
|
|
1748
|
+
</div>
|
|
1749
|
+
</div>
|
|
1750
|
+
</div>
|
|
1751
|
+
</section>
|
|
1752
|
+
|
|
1753
|
+
<section class="workbench-reference-bid-risk-table grid min-h-[8.75rem] grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-md border border-slate-200 bg-white">
|
|
1754
|
+
<div class="grid h-9 grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-2 border-b border-slate-200 px-3">
|
|
1755
|
+
<i class="h-4 w-1.5 rounded-full bg-emerald-600" />
|
|
1756
|
+
<h4 class="truncate text-sm font-semibold leading-5 text-slate-900">关键风险与待确认事项</h4>
|
|
1757
|
+
<span class="truncate text-xs font-semibold text-slate-500">责任角色 / 协同动作</span>
|
|
1758
|
+
</div>
|
|
1759
|
+
<div class="grid min-h-0 overflow-hidden">
|
|
1760
|
+
<div class="grid grid-cols-[minmax(0,1.05fr)_minmax(0,0.62fr)_minmax(0,1.58fr)] border-b border-slate-200 bg-slate-50 px-3 py-1.5 font-semibold text-slate-500">
|
|
1761
|
+
<span class="truncate">待确认事项</span>
|
|
1762
|
+
<span class="truncate">责任角色</span>
|
|
1763
|
+
<span class="truncate">协同动作</span>
|
|
1764
|
+
</div>
|
|
1765
|
+
<div
|
|
1766
|
+
v-for="(item, index) in referenceBidRiskRows(effectiveData as CustomCanvasData).slice(0, 5)"
|
|
1767
|
+
:key="`bid-risk-${index}`"
|
|
1768
|
+
:class="['grid min-h-0 grid-cols-[minmax(0,1.05fr)_minmax(0,0.62fr)_minmax(0,1.58fr)] items-center border-b border-slate-100 px-3 py-1.5 last:border-b-0', nestedBlockToneClass(item) === 'critical' ? 'bg-red-50' : nestedBlockToneClass(item) === 'warning' ? 'bg-amber-50' : nestedBlockToneClass(item) === 'healthy' ? 'bg-emerald-50' : 'bg-white']"
|
|
1769
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1770
|
+
>
|
|
1771
|
+
<span class="min-w-0 truncate font-semibold text-slate-800">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1772
|
+
<span class="min-w-0 truncate font-semibold text-slate-600">{{ textValue(item.owner, '待确认') }}</span>
|
|
1773
|
+
<span class="min-w-0 truncate font-semibold text-slate-700">{{ nestedBlockItemDetail(item) || referenceBidSanitizedMetricValue(item, '待确认') }}</span>
|
|
1774
|
+
</div>
|
|
1775
|
+
</div>
|
|
1776
|
+
</section>
|
|
1777
|
+
|
|
1778
|
+
<section class="grid min-h-[6.25rem] grid-cols-2 gap-2 overflow-hidden">
|
|
1779
|
+
<div
|
|
1780
|
+
v-for="(item, index) in referenceBidConclusionItems(effectiveData as CustomCanvasData)"
|
|
1781
|
+
:key="`bid-conclusion-${index}`"
|
|
1782
|
+
:class="['grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-md border px-3 py-2', nestedBlockToneClass(item) === 'critical' ? 'border-red-200 bg-red-50' : nestedBlockToneClass(item) === 'warning' ? 'border-amber-200 bg-amber-50' : nestedBlockToneClass(item) === 'healthy' ? 'border-emerald-200 bg-emerald-50' : 'border-slate-200 bg-white']"
|
|
1783
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1784
|
+
>
|
|
1785
|
+
<div class="grid grid-cols-[minmax(0,1fr)_auto] items-center gap-2">
|
|
1786
|
+
<strong class="truncate text-sm leading-5 text-slate-900">{{ nestedBlockItemLabel(item, index) }}</strong>
|
|
1787
|
+
<span :class="nestedBlockPillClasses(item)" :title="referenceBidSanitizedMetricValue(item, '待确认')">{{ referenceBidSanitizedMetricValue(item, '待确认') }}</span>
|
|
1788
|
+
</div>
|
|
1789
|
+
<span class="mt-1 max-h-12 overflow-hidden text-slate-700" :title="nestedBlockItemDetail(item) || referenceBidSanitizedMetricValue(item, '待确认')">{{ nestedBlockItemDetail(item) || referenceBidSanitizedMetricValue(item, '待确认') }}</span>
|
|
1790
|
+
</div>
|
|
1791
|
+
</section>
|
|
1792
|
+
|
|
1793
|
+
<section class="grid min-h-[4.25rem] grid-cols-[minmax(0,1fr)_auto] items-center gap-3 overflow-hidden rounded-md border border-amber-200 bg-amber-50 px-3 py-2">
|
|
1794
|
+
<div class="min-w-0">
|
|
1795
|
+
<h4 class="truncate text-sm font-semibold leading-5 text-slate-900">待补口径与问数动作</h4>
|
|
1796
|
+
<p class="mt-1 truncate text-xs font-semibold text-slate-700">真实数据问数前仅作截图预览,请补充指标、表、字段或系统口径后再刷新。</p>
|
|
1797
|
+
</div>
|
|
1798
|
+
<div class="flex max-w-[32rem] flex-wrap justify-end gap-1.5 overflow-hidden">
|
|
1799
|
+
<span
|
|
1800
|
+
v-for="(item, index) in referenceBidDataBoundaryItems(effectiveData as CustomCanvasData)"
|
|
1801
|
+
:key="`bid-boundary-${index}`"
|
|
1802
|
+
:class="nestedBlockPillClasses(item)"
|
|
1803
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1804
|
+
>
|
|
1805
|
+
{{ nestedBlockItemLabel(item, index) }}:{{ referenceBidSanitizedMetricValue(item, '待确认') }}
|
|
1806
|
+
</span>
|
|
1807
|
+
</div>
|
|
1808
|
+
</section>
|
|
1809
|
+
</div>
|
|
1810
|
+
<div
|
|
1811
|
+
v-else-if="customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData) === 'businessMetricMatrix'"
|
|
1812
|
+
:class="[
|
|
1813
|
+
'workbench-reference-business-metric-matrix-panel min-h-0 flex-1 overflow-hidden px-3 pb-3',
|
|
1814
|
+
businessMetricMatrixLargePanel(effectiveBlock)
|
|
1815
|
+
? 'workbench-reference-business-metric-matrix-large-panel grid grid-cols-[minmax(0,1.05fr)_minmax(0,1.25fr)] grid-rows-[minmax(0,1fr)_auto] gap-2.5'
|
|
1816
|
+
: 'workbench-reference-business-metric-matrix-compact-panel grid grid-cols-[1.08fr_1.08fr_0.92fr] grid-rows-[minmax(0,0.64fr)_minmax(0,0.36fr)] gap-2'
|
|
1817
|
+
]"
|
|
1818
|
+
>
|
|
1819
|
+
<template v-if="businessMetricMatrixLargePanel(effectiveBlock)">
|
|
1820
|
+
<section class="workbench-reference-business-metric-large-primary grid min-h-0 grid-rows-[auto_minmax(0,1fr)_auto] overflow-hidden rounded-md border border-slate-200 bg-slate-50 px-3 py-2">
|
|
1821
|
+
<h4 class="truncate text-sm font-semibold leading-5 text-slate-900" title="指标矩阵">指标矩阵</h4>
|
|
1822
|
+
<div class="mt-2 grid min-h-0 grid-cols-2 gap-2 overflow-hidden" style="grid-auto-rows: minmax(0, 1fr);">
|
|
1823
|
+
<div
|
|
1824
|
+
v-for="(item, index) in referenceBusinessMetricItems(effectiveData as CustomCanvasData).slice(0, 4)"
|
|
1825
|
+
:key="`business-metric-large-${index}`"
|
|
1826
|
+
:class="['workbench-reference-business-metric-tile grid min-h-0 grid-rows-[auto_minmax(0,1fr)] content-center overflow-hidden rounded-md border bg-white px-2.5 py-2', nestedBlockToneClass(item) === 'critical' ? 'border-red-100' : nestedBlockToneClass(item) === 'warning' ? 'border-amber-100' : 'border-slate-200']"
|
|
1827
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1828
|
+
>
|
|
1829
|
+
<span class="max-w-full truncate text-xs font-semibold leading-4 text-slate-500" :title="nestedBlockItemLabel(item, index)">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1830
|
+
<strong class="workbench-reference-business-metric-value mt-1 max-w-full truncate text-[clamp(1rem,1.4vw,1.35rem)] font-bold leading-6 text-slate-950" :title="nestedBlockItemValue(item)">
|
|
1831
|
+
{{ nestedBlockItemValue(item) || '--' }}
|
|
1832
|
+
</strong>
|
|
1833
|
+
</div>
|
|
1834
|
+
</div>
|
|
1835
|
+
<div class="workbench-reference-business-metric-large-summary mt-2 grid min-h-0 grid-cols-2 gap-2 overflow-hidden">
|
|
1836
|
+
<div
|
|
1837
|
+
v-for="(item, index) in referenceBusinessMetricItems(effectiveData as CustomCanvasData).slice(4, 8)"
|
|
1838
|
+
:key="`business-metric-summary-large-${index}`"
|
|
1839
|
+
class="grid min-h-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-2 overflow-hidden rounded-md border border-slate-200 bg-white px-2 py-1 text-xs leading-4"
|
|
1840
|
+
:title="nestedBlockItemTitle(item, index + 4)"
|
|
1841
|
+
>
|
|
1842
|
+
<span class="truncate font-semibold text-slate-600">{{ nestedBlockItemLabel(item, index + 4) }}</span>
|
|
1843
|
+
<b class="max-w-[4.25rem] truncate text-right text-slate-900">{{ nestedBlockItemValue(item) || '--' }}</b>
|
|
1844
|
+
</div>
|
|
1845
|
+
</div>
|
|
1846
|
+
</section>
|
|
1847
|
+
<section class="workbench-reference-business-metric-large-flow grid min-h-0 grid-rows-[minmax(0,0.52fr)_minmax(0,0.48fr)] gap-2 overflow-hidden">
|
|
1848
|
+
<div class="workbench-reference-business-chart-bars grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-md border border-slate-200 bg-white px-3 py-2">
|
|
1849
|
+
<h4 class="truncate text-sm font-semibold leading-5 text-slate-900" :title="effectiveBlock.title">趋势摘要</h4>
|
|
1850
|
+
<div class="mt-2 grid min-h-0 content-start gap-2 overflow-hidden">
|
|
1851
|
+
<div
|
|
1852
|
+
v-for="(item, index) in referenceBusinessChartItems(effectiveData as CustomCanvasData).slice(0, 4)"
|
|
1853
|
+
:key="`business-chart-large-${index}`"
|
|
1854
|
+
class="grid grid-cols-[4.75rem_minmax(0,1fr)_3.5rem] items-center gap-2 overflow-hidden text-sm leading-5"
|
|
1855
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1856
|
+
>
|
|
1857
|
+
<span class="truncate text-slate-600">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1858
|
+
<span class="h-3 overflow-hidden rounded-full bg-slate-200"><i :class="nestedBlockBarClasses(item)" :style="nestedBlockBarStyle(item, 62)" /></span>
|
|
1859
|
+
<b class="truncate text-right font-semibold text-slate-700">{{ nestedBlockItemValue(item) || nestedBlockItemProgress(item, 62) }}</b>
|
|
1860
|
+
</div>
|
|
1861
|
+
</div>
|
|
1862
|
+
</div>
|
|
1863
|
+
<div class="grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-md border border-slate-200 bg-slate-50 px-2 py-2">
|
|
1864
|
+
<h4 class="truncate text-sm font-semibold leading-5 text-slate-900">业务动态</h4>
|
|
1865
|
+
<div class="mt-2 grid min-h-0 gap-1 overflow-hidden" style="grid-auto-rows: minmax(0, 1fr);">
|
|
1866
|
+
<div
|
|
1867
|
+
v-for="(item, index) in referenceBusinessListItems(effectiveData as CustomCanvasData).slice(0, 4)"
|
|
1868
|
+
:key="`business-list-large-${index}`"
|
|
1869
|
+
class="workbench-reference-business-list-row grid min-h-0 grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-1.5 overflow-hidden rounded border border-slate-100 bg-white px-2 py-1 text-xs"
|
|
1870
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1871
|
+
>
|
|
1872
|
+
<i :class="nestedBlockDotClasses(item)" />
|
|
1873
|
+
<span class="min-w-0 truncate font-semibold leading-4 text-slate-700">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1874
|
+
<b class="max-w-[5rem] truncate text-right leading-4 text-slate-900" :title="nestedBlockItemValue(item)">{{ nestedBlockItemValue(item) }}</b>
|
|
1875
|
+
</div>
|
|
1876
|
+
</div>
|
|
1877
|
+
</div>
|
|
1878
|
+
</section>
|
|
1879
|
+
<section class="col-span-2 grid min-h-0 grid-cols-4 gap-2 overflow-hidden">
|
|
1880
|
+
<div
|
|
1881
|
+
v-for="(item, index) in referenceBusinessListItems(effectiveData as CustomCanvasData).slice(0, 4)"
|
|
1882
|
+
:key="`business-footer-large-${index}`"
|
|
1883
|
+
class="grid min-h-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-2 overflow-hidden rounded-md border border-slate-200 bg-white px-2 py-1.5 text-xs"
|
|
1884
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1885
|
+
>
|
|
1886
|
+
<span class="truncate font-semibold text-slate-600">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1887
|
+
<span :class="nestedBlockPillClasses(item)" :title="nestedBlockItemValue(item) || nestedBlockItemDetail(item)">{{ nestedBlockItemValue(item) || nestedBlockItemDetail(item) || '待确认' }}</span>
|
|
1888
|
+
</div>
|
|
1889
|
+
</section>
|
|
1890
|
+
</template>
|
|
1891
|
+
<template v-else>
|
|
1892
|
+
<section class="grid min-h-0 grid-cols-2 gap-1.5 overflow-hidden">
|
|
1893
|
+
<div
|
|
1894
|
+
v-for="(item, index) in referenceBusinessMetricItems(effectiveData as CustomCanvasData)"
|
|
1895
|
+
:key="`business-metric-${index}`"
|
|
1896
|
+
class="workbench-reference-business-metric-tile grid min-h-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-1.5 overflow-hidden rounded-md border border-slate-200 bg-slate-50 px-2 py-1.5 text-xs"
|
|
1897
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1898
|
+
>
|
|
1899
|
+
<span class="min-w-0 truncate font-semibold leading-4 text-slate-600" :title="nestedBlockItemLabel(item, index)">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1900
|
+
<strong class="workbench-reference-business-metric-value max-w-[4.25rem] shrink-0 truncate text-right text-sm font-bold leading-5 text-slate-900" :title="nestedBlockItemValue(item)">
|
|
1901
|
+
{{ nestedBlockItemValue(item) || '--' }}
|
|
1902
|
+
</strong>
|
|
1903
|
+
</div>
|
|
1904
|
+
</section>
|
|
1905
|
+
<section class="workbench-reference-business-chart-bars grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-md border border-slate-200 bg-white px-2 py-2">
|
|
1906
|
+
<h4 class="truncate text-sm font-semibold leading-5 text-slate-900" :title="effectiveBlock.title">趋势摘要</h4>
|
|
1907
|
+
<div class="mt-2 grid min-h-0 grid-cols-6 items-end gap-1.5 overflow-hidden border-b border-slate-200 px-1 pb-1.5">
|
|
1908
|
+
<div
|
|
1909
|
+
v-for="(item, index) in referenceBusinessChartItems(effectiveData as CustomCanvasData)"
|
|
1910
|
+
:key="`business-chart-${index}`"
|
|
1911
|
+
class="grid h-full min-h-0 grid-rows-[minmax(0,1fr)_auto] items-end gap-1 text-center text-xs text-slate-500"
|
|
1912
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1913
|
+
>
|
|
1914
|
+
<span class="flex h-full min-h-0 items-end justify-center"><i :class="referenceOpsTrendBarClasses(item)" :style="{ height: nestedBlockItemProgress(item, 58), width: '62%' }" /></span>
|
|
1915
|
+
<span class="truncate">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1916
|
+
</div>
|
|
1917
|
+
</div>
|
|
1918
|
+
</section>
|
|
1919
|
+
<section class="row-span-2 grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-md border border-slate-200 bg-slate-50 px-2 py-2">
|
|
1920
|
+
<h4 class="truncate text-sm font-semibold leading-5 text-slate-900">业务动态</h4>
|
|
1921
|
+
<div class="mt-2 grid min-h-0 gap-1 overflow-hidden" style="grid-auto-rows: minmax(0, 1fr);">
|
|
1922
|
+
<div
|
|
1923
|
+
v-for="(item, index) in referenceBusinessListItems(effectiveData as CustomCanvasData)"
|
|
1924
|
+
:key="`business-list-${index}`"
|
|
1925
|
+
class="workbench-reference-business-list-row grid min-h-0 grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-1.5 overflow-hidden rounded border border-slate-100 bg-white px-2 py-1 text-xs"
|
|
1926
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1927
|
+
>
|
|
1928
|
+
<i :class="nestedBlockDotClasses(item)" />
|
|
1929
|
+
<span class="min-w-0 truncate font-semibold leading-4 text-slate-700">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1930
|
+
<b class="max-w-[4.75rem] truncate text-right leading-4 text-slate-900" :title="nestedBlockItemValue(item)">{{ nestedBlockItemValue(item) }}</b>
|
|
1931
|
+
</div>
|
|
1932
|
+
</div>
|
|
1933
|
+
</section>
|
|
1934
|
+
<section class="col-span-2 grid min-h-0 grid-cols-3 gap-1.5 overflow-hidden">
|
|
1935
|
+
<div
|
|
1936
|
+
v-for="(item, index) in referenceBusinessListItems(effectiveData as CustomCanvasData).slice(0, 3)"
|
|
1937
|
+
:key="`business-footer-${index}`"
|
|
1938
|
+
class="grid min-h-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-2 overflow-hidden rounded-md border border-slate-200 bg-white px-2 py-1.5 text-xs"
|
|
1939
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
1940
|
+
>
|
|
1941
|
+
<span class="truncate font-semibold text-slate-600">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1942
|
+
<span :class="nestedBlockPillClasses(item)" :title="nestedBlockItemValue(item) || nestedBlockItemDetail(item)">{{ nestedBlockItemValue(item) || nestedBlockItemDetail(item) || '待确认' }}</span>
|
|
1943
|
+
</div>
|
|
1944
|
+
</section>
|
|
1945
|
+
</template>
|
|
1946
|
+
</div>
|
|
1947
|
+
<div
|
|
1948
|
+
v-else-if="customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData) === 'asset'"
|
|
1949
|
+
class="workbench-reference-asset-panel grid min-h-0 flex-1 grid-cols-[1fr_1.08fr] gap-1.5 overflow-hidden px-1 pb-1 text-xs leading-4"
|
|
1950
|
+
style="grid-template-columns: minmax(0, 1fr) minmax(0, 1.08fr);"
|
|
1951
|
+
>
|
|
1952
|
+
<section class="workbench-reference-asset-left-column grid min-h-0 grid-rows-[auto_minmax(0,0.44fr)_minmax(0,0.56fr)] gap-1 overflow-hidden">
|
|
1953
|
+
<h4 class="truncate text-xs font-semibold text-slate-500">全域 IT 资产台账</h4>
|
|
1954
|
+
<div class="workbench-reference-asset-ledger-grid grid h-full min-h-0 grid-cols-2 gap-1 overflow-hidden" style="grid-template-rows: repeat(2, minmax(0, 1fr));">
|
|
1955
|
+
<div v-for="(item, index) in referenceAssetLedgerItems(effectiveData as CustomCanvasData).slice(0, 4)" :key="`asset-ledger-${index}`" class="grid min-h-0 grid-rows-[minmax(0,1fr)_auto] content-center gap-0.5 overflow-hidden rounded border border-slate-100 bg-slate-50 px-1.5 py-0.5 text-center">
|
|
1956
|
+
<span class="min-w-0 truncate text-xs leading-4 text-slate-500" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1957
|
+
<strong class="workbench-reference-metric-value max-w-full truncate text-sm leading-none text-slate-900" :title="nestedBlockItemValue(item)">{{ nestedBlockItemValue(item) }}</strong>
|
|
1958
|
+
</div>
|
|
1959
|
+
</div>
|
|
1960
|
+
<div class="workbench-reference-asset-exception-list grid h-full min-h-0 gap-1 overflow-hidden" style="grid-auto-rows: minmax(0, 1fr);">
|
|
1961
|
+
<div v-for="(item, index) in referenceAssetExceptionItems(effectiveData as CustomCanvasData).slice(0, 3)" :key="`asset-exception-${index}`" class="grid min-h-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-1.5 overflow-hidden rounded border border-slate-100 bg-slate-50 px-1.5 py-0.5 text-xs leading-4">
|
|
1962
|
+
<span class="min-w-0 truncate font-semibold text-slate-800" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1963
|
+
<span :class="['workbench-reference-asset-value-pill', ...nestedBlockPillClasses(item)]" :title="nestedBlockItemValue(item)">{{ nestedBlockItemValue(item) }}</span>
|
|
1964
|
+
</div>
|
|
1965
|
+
</div>
|
|
1966
|
+
</section>
|
|
1967
|
+
<section class="workbench-reference-asset-right-column grid min-h-0 grid-rows-[auto_minmax(0,0.62fr)_minmax(0,0.38fr)] gap-1 overflow-hidden">
|
|
1968
|
+
<h4 class="truncate text-xs font-semibold text-slate-500">IT 成本分析</h4>
|
|
1969
|
+
<div class="workbench-reference-cost-donut-card grid h-full min-h-0 items-center overflow-hidden rounded border border-slate-100 bg-slate-50 p-1.5" style="grid-template-columns: minmax(2.5rem, min(5.5rem, 34%)) minmax(0, 1fr);">
|
|
1970
|
+
<div class="workbench-reference-cost-donut-ring grid place-items-center rounded-full text-xs font-semibold leading-4 text-slate-500" :style="referenceCostDonutStyle(effectiveData as CustomCanvasData)">预算</div>
|
|
1971
|
+
<div class="grid min-h-0 min-w-0 gap-0.5 overflow-hidden text-xs leading-4" style="grid-auto-rows: minmax(0, 1fr);">
|
|
1972
|
+
<div v-for="(item, index) in referenceCostDonutItems(effectiveData as CustomCanvasData).slice(0, 4)" :key="`asset-cost-donut-${index}`" class="grid min-h-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-1 overflow-hidden" style="grid-template-columns: minmax(0, 1fr) auto;">
|
|
1973
|
+
<span class="truncate text-slate-500" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1974
|
+
<b class="max-w-[4.5rem] truncate text-slate-800" :title="nestedBlockItemValue(item)">{{ nestedBlockItemValue(item) }}</b>
|
|
1975
|
+
</div>
|
|
1976
|
+
</div>
|
|
1977
|
+
</div>
|
|
1978
|
+
<div class="workbench-reference-cost-list grid h-full min-h-0 gap-1 overflow-hidden" style="grid-auto-rows: minmax(0, 1fr);">
|
|
1979
|
+
<div v-for="(item, index) in referenceCostItems(effectiveData as CustomCanvasData).slice(0, 3)" :key="`asset-cost-${index}`" class="grid min-h-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-1.5 overflow-hidden rounded border border-slate-100 bg-slate-50 px-1.5 py-0.5 text-xs leading-4" style="grid-template-columns: minmax(0, 1fr) auto;">
|
|
1980
|
+
<span class="min-w-0 truncate font-semibold text-slate-800" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1981
|
+
<span :class="['workbench-reference-asset-value-pill', ...nestedBlockPillClasses(item)]" :title="nestedBlockItemValue(item)">{{ nestedBlockItemValue(item) }}</span>
|
|
1982
|
+
</div>
|
|
1983
|
+
</div>
|
|
1984
|
+
</section>
|
|
1985
|
+
</div>
|
|
1986
|
+
<div
|
|
1987
|
+
v-else-if="customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData) === 'ops'"
|
|
1988
|
+
class="workbench-reference-ops-panel grid min-h-0 flex-1 grid-cols-2 gap-1.5 overflow-hidden px-1 pb-1 text-xs leading-4"
|
|
1989
|
+
>
|
|
1990
|
+
<section class="workbench-reference-ops-left-column grid min-h-0 grid-rows-[auto_minmax(0,0.58fr)_minmax(0,0.42fr)] gap-1 overflow-hidden">
|
|
1991
|
+
<h4 class="truncate text-xs font-semibold text-slate-500">全局服务监控</h4>
|
|
1992
|
+
<div class="workbench-reference-ops-service-list grid h-full min-h-0 content-start gap-1 overflow-hidden" style="grid-auto-rows: minmax(16px, 1fr);">
|
|
1993
|
+
<div v-for="(item, index) in referenceOpsServiceItems(effectiveData as CustomCanvasData).slice(0, 4)" :key="`ops-service-${index}`" class="grid min-h-0 grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-1 overflow-hidden rounded border border-slate-100 bg-slate-50 px-1.5 py-0 text-xs leading-4" :title="`${nestedBlockItemTitle(item, index)} ${nestedBlockItemValue(item) || '正常'}`">
|
|
1994
|
+
<i :class="nestedBlockDotClasses(item)" />
|
|
1995
|
+
<span class="min-w-0 truncate font-semibold text-slate-800" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
1996
|
+
<span :class="nestedBlockPillClasses(item)" :title="nestedBlockItemValue(item) || '正常'">{{ nestedBlockItemValue(item) || '正常' }}</span>
|
|
1997
|
+
</div>
|
|
1998
|
+
</div>
|
|
1999
|
+
<div class="workbench-reference-ops-resource-list grid h-full min-h-0 gap-0.5 overflow-hidden" style="grid-template-rows: repeat(4, minmax(0, 1fr));">
|
|
2000
|
+
<div v-for="(item, index) in referenceOpsResourceItems(effectiveData as CustomCanvasData).slice(0, 4)" :key="`ops-resource-${index}`" class="grid min-h-0 grid-cols-[2.25rem_minmax(0,1fr)_2rem] items-center gap-1.5 text-xs leading-4" style="grid-template-columns: 2.25rem minmax(0, 1fr) 2rem;">
|
|
2001
|
+
<span class="truncate text-slate-500" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
2002
|
+
<span class="h-2 overflow-hidden rounded-full bg-slate-200"><i :class="nestedBlockBarClasses(item)" :style="nestedBlockBarStyle(item, 60)" /></span>
|
|
2003
|
+
<b class="truncate text-right font-semibold text-slate-600" :title="nestedBlockItemValue(item) || nestedBlockItemProgress(item)">{{ nestedBlockItemValue(item) || nestedBlockItemProgress(item) }}</b>
|
|
2004
|
+
</div>
|
|
2005
|
+
</div>
|
|
2006
|
+
</section>
|
|
2007
|
+
<section class="workbench-reference-ops-right-column grid min-h-0 grid-rows-[auto_auto_minmax(0,1fr)] gap-1 overflow-hidden">
|
|
2008
|
+
<h4 class="truncate text-xs font-semibold text-slate-500">故障 & 告警中心</h4>
|
|
2009
|
+
<div class="workbench-reference-ops-incident-list grid min-h-0 content-start gap-1 overflow-hidden" style="grid-auto-rows: minmax(0, 1fr);">
|
|
2010
|
+
<div v-for="(item, index) in referenceOpsIncidentItems(effectiveData as CustomCanvasData).slice(0, 3)" :key="`ops-incident-${index}`" class="grid min-h-0 grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-1.5 overflow-hidden rounded border border-slate-100 bg-slate-50 px-1.5 py-0.5 text-xs leading-4" style="grid-template-columns: auto minmax(0, 1fr) auto;">
|
|
2011
|
+
<span
|
|
2012
|
+
:class="[
|
|
2013
|
+
'inline-block h-4 max-w-[2rem] shrink-0 truncate rounded border px-1 text-xs font-semibold leading-4',
|
|
2014
|
+
nestedBlockToneClass(item) === 'critical' ? 'border-red-200 bg-red-50 text-red-600' : nestedBlockToneClass(item) === 'warning' ? 'border-amber-200 bg-amber-50 text-amber-700' : 'border-slate-200 bg-white text-slate-600',
|
|
2015
|
+
]"
|
|
2016
|
+
:title="nestedBlockItemSeverity(item)"
|
|
2017
|
+
>
|
|
2018
|
+
{{ nestedBlockItemSeverity(item) }}
|
|
2019
|
+
</span>
|
|
2020
|
+
<span class="min-w-0">
|
|
2021
|
+
<strong class="block truncate text-xs leading-4 text-slate-800" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</strong>
|
|
2022
|
+
<span class="block truncate text-xs leading-4 text-slate-500" :title="nestedBlockItemDetail(item)">{{ nestedBlockItemDetail(item) }}</span>
|
|
2023
|
+
</span>
|
|
2024
|
+
<span class="shrink-0 text-xs font-medium text-slate-500" :title="nestedBlockItemTime(item)">{{ nestedBlockItemTime(item) }}</span>
|
|
2025
|
+
</div>
|
|
2026
|
+
</div>
|
|
2027
|
+
<div class="workbench-reference-ops-trend-card grid h-full min-h-0 grid-rows-[auto_minmax(0,1fr)] gap-0.5 overflow-hidden rounded border border-slate-100 bg-slate-50 px-1.5 py-1">
|
|
2028
|
+
<div class="flex items-center justify-between gap-2 text-xs leading-4">
|
|
2029
|
+
<span class="truncate font-semibold text-slate-500">近七日故障趋势</span>
|
|
2030
|
+
<b class="text-slate-800">合计 58 件</b>
|
|
2031
|
+
</div>
|
|
2032
|
+
<div class="grid min-h-0 grid-cols-7 items-stretch gap-1 overflow-hidden">
|
|
2033
|
+
<div v-for="(item, index) in referenceOpsTrendChartItems(effectiveData as CustomCanvasData)" :key="`ops-trend-${index}`" class="grid h-full min-h-0 grid-rows-[auto_minmax(0,1fr)_auto] gap-0.5 text-center text-xs text-slate-500">
|
|
2034
|
+
<b class="truncate text-slate-700">{{ nestedBlockItemValue(item) || nestedBlockItemLabel(item, index) }}</b>
|
|
2035
|
+
<span class="flex h-full min-h-0 items-end justify-center"><i :class="referenceOpsTrendBarClasses(item)" :style="{ height: textValue(item.barHeight, '60%'), minHeight: '12px', width: '46%' }" /></span>
|
|
2036
|
+
<span class="truncate">{{ nestedBlockItemValue(item) ? nestedBlockItemLabel(item, index) : `周${index + 1}` }}</span>
|
|
2037
|
+
</div>
|
|
2038
|
+
</div>
|
|
2039
|
+
</div>
|
|
2040
|
+
</section>
|
|
2041
|
+
</div>
|
|
2042
|
+
<div
|
|
2043
|
+
v-else-if="customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData) === 'security'"
|
|
2044
|
+
class="workbench-reference-security-panel grid min-h-0 flex-1 grid-cols-[1.18fr_1fr] gap-1.5 overflow-hidden px-1 pb-1 text-xs leading-4"
|
|
2045
|
+
>
|
|
2046
|
+
<section class="workbench-reference-security-left-column grid min-h-0 gap-1 overflow-hidden">
|
|
2047
|
+
<h4 class="truncate text-xs font-semibold text-slate-500">安全风险总览</h4>
|
|
2048
|
+
<div class="workbench-reference-security-score-card grid h-full min-h-0 grid-cols-[minmax(128px,0.46fr)_minmax(0,1fr)] gap-1 overflow-hidden rounded-md bg-[#101820] p-2 text-white">
|
|
2049
|
+
<div class="workbench-reference-security-score-main grid min-h-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-2">
|
|
2050
|
+
<div class="min-w-0 flex items-end gap-1">
|
|
2051
|
+
<strong class="text-3xl leading-none">{{ nestedBlockSecurityScore(referenceSecurityScoreBlock(effectiveData as CustomCanvasData)) }}</strong>
|
|
2052
|
+
<span class="pb-0.5 text-xs leading-4 text-slate-300">/ 100</span>
|
|
2053
|
+
</div>
|
|
2054
|
+
<span class="workbench-reference-security-score-ring grid place-items-center rounded-full border-[6px] border-emerald-500/80 bg-slate-950 text-sm font-semibold leading-none text-white">{{ nestedBlockSecurityScoreRingLabel(referenceSecurityScoreBlock(effectiveData as CustomCanvasData)) }}</span>
|
|
2055
|
+
</div>
|
|
2056
|
+
<div class="workbench-reference-security-score-metrics grid h-full min-h-0 shrink-0 gap-1">
|
|
2057
|
+
<div v-for="(item, index) in nestedBlockSecurityMetrics(referenceSecurityScoreBlock(effectiveData as CustomCanvasData)).slice(0, 3)" :key="`security-score-${index}`" class="workbench-reference-security-score-metric flex min-w-0 items-center gap-1 overflow-hidden rounded border border-slate-700 bg-slate-800 px-1.5 py-0.5">
|
|
2058
|
+
<strong class="max-w-[2.25rem] shrink-0 truncate text-sm leading-4" :title="nestedBlockItemValue(item) || nestedBlockItemTitle(item, index)">{{ nestedBlockItemValue(item) || nestedBlockItemLabel(item, index) }}</strong>
|
|
2059
|
+
<span class="min-w-0 flex-1 truncate text-xs leading-4 text-slate-400" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemValue(item) ? nestedBlockItemLabel(item, index) : '' }}</span>
|
|
2060
|
+
</div>
|
|
2061
|
+
</div>
|
|
2062
|
+
</div>
|
|
2063
|
+
<div class="workbench-reference-security-risk-list grid h-full min-h-0 content-start gap-1 overflow-hidden">
|
|
2064
|
+
<div v-for="(item, index) in referenceSecurityRiskItems(effectiveData as CustomCanvasData).slice(0, 3)" :key="`security-risk-${index}`" class="grid min-h-[1.25rem] grid-cols-[minmax(0,1fr)_auto] items-center gap-1.5 overflow-hidden rounded border border-slate-100 bg-slate-50 px-1.5 py-0 text-xs leading-4">
|
|
2065
|
+
<span class="min-w-0 truncate font-semibold text-slate-800" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
2066
|
+
<span :class="nestedBlockPillClasses(item)" :title="nestedBlockItemValue(item)">{{ nestedBlockItemValue(item) }}</span>
|
|
2067
|
+
</div>
|
|
2068
|
+
</div>
|
|
2069
|
+
</section>
|
|
2070
|
+
<section class="workbench-reference-security-right-column grid min-h-0 grid-rows-[auto_minmax(0,1fr)] gap-1 overflow-hidden">
|
|
2071
|
+
<h4 class="truncate text-xs font-semibold text-slate-500">合规与审计</h4>
|
|
2072
|
+
<div class="workbench-reference-security-compliance-list grid h-full min-h-0 gap-1 overflow-hidden">
|
|
2073
|
+
<div v-for="(item, index) in referenceSecurityComplianceItems(effectiveData as CustomCanvasData).slice(0, 6)" :key="`security-compliance-${index}`" class="grid min-h-[1.5rem] grid-cols-[minmax(0,1fr)_auto] items-center gap-1.5 overflow-hidden rounded border border-slate-100 bg-slate-50 px-1.5 py-0.5 text-xs leading-4">
|
|
2074
|
+
<span class="min-w-0 truncate font-semibold text-slate-800" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
2075
|
+
<span :class="nestedBlockPillClasses(item)" :title="nestedBlockItemValue(item)">{{ nestedBlockItemValue(item) }}</span>
|
|
2076
|
+
</div>
|
|
2077
|
+
</div>
|
|
2078
|
+
</section>
|
|
2079
|
+
</div>
|
|
2080
|
+
<div
|
|
2081
|
+
v-else-if="customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData) === 'project'"
|
|
2082
|
+
class="workbench-reference-project-panel grid min-h-0 flex-1 grid-cols-[1.16fr_0.84fr] gap-1.5 overflow-hidden px-1 pb-1 text-xs leading-4"
|
|
2083
|
+
style="grid-template-columns: minmax(0, 1.16fr) minmax(0, 0.84fr);"
|
|
2084
|
+
>
|
|
2085
|
+
<section class="workbench-reference-project-left-column grid min-h-0 grid-rows-[auto_minmax(5.5rem,0.68fr)_minmax(4.25rem,0.32fr)] gap-1 overflow-hidden">
|
|
2086
|
+
<h4 class="truncate text-xs font-semibold text-slate-500">重点 IT 项目看板</h4>
|
|
2087
|
+
<div class="workbench-reference-project-progress-list grid h-full min-h-0 gap-1 overflow-hidden" style="grid-template-rows: repeat(4, minmax(1.25rem, 1fr));">
|
|
2088
|
+
<div v-for="(item, index) in referenceProjectProgressItems(effectiveData as CustomCanvasData).slice(0, 4)" :key="`project-progress-${index}`" class="grid min-h-[1.25rem] grid-cols-[minmax(0,1fr)_3rem_auto] items-center gap-1.5 overflow-hidden rounded border border-slate-100 bg-slate-50 px-1.5 py-0 text-xs leading-4" style="grid-template-columns: minmax(0, 1fr) 3rem auto;">
|
|
2089
|
+
<span class="min-w-0 truncate font-semibold text-slate-800">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
2090
|
+
<span class="h-2 overflow-hidden rounded-full bg-slate-200"><i :class="nestedBlockBarClasses(item)" :style="nestedBlockBarStyle(item, 52)" /></span>
|
|
2091
|
+
<span :class="nestedBlockPillClasses(item)">{{ nestedBlockItemValue(item) || nestedBlockItemProgress(item) }}</span>
|
|
2092
|
+
</div>
|
|
2093
|
+
</div>
|
|
2094
|
+
<div class="workbench-reference-project-efficiency-list grid h-full min-h-0 gap-1 overflow-hidden" style="grid-auto-rows: minmax(1.25rem, 1fr);">
|
|
2095
|
+
<div v-for="(item, index) in referenceEfficiencyItems(effectiveData as CustomCanvasData).slice(0, 3)" :key="`project-efficiency-${index}`" class="grid min-h-[1.25rem] grid-cols-[minmax(0,1fr)_auto] items-center gap-1.5 overflow-hidden rounded border border-slate-100 bg-slate-50 px-1.5 py-0 text-xs leading-4" style="grid-template-columns: minmax(0, 1fr) auto;">
|
|
2096
|
+
<span class="min-w-0 truncate font-semibold text-slate-800">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
2097
|
+
<span :class="nestedBlockPillClasses(item)">{{ nestedBlockItemValue(item) }}</span>
|
|
2098
|
+
</div>
|
|
2099
|
+
</div>
|
|
2100
|
+
</section>
|
|
2101
|
+
<section class="workbench-reference-project-right-column grid min-h-0 grid-rows-[auto_minmax(4.75rem,0.45fr)_minmax(3.25rem,0.28fr)_minmax(2.75rem,0.27fr)] gap-1 overflow-hidden">
|
|
2102
|
+
<h4 class="truncate text-xs font-semibold text-slate-500">个人待办快捷区</h4>
|
|
2103
|
+
<div class="workbench-reference-project-todo-grid grid h-full min-h-0 grid-cols-2 gap-1 overflow-hidden" style="grid-template-rows: repeat(2, minmax(2rem, 1fr));">
|
|
2104
|
+
<div v-for="(item, index) in referenceTodoItems(effectiveData as CustomCanvasData)" :key="`project-todo-${index}`" class="grid h-full min-h-[2rem] place-items-center overflow-hidden rounded border border-slate-100 bg-slate-50 px-1.5 py-0.5 text-center">
|
|
2105
|
+
<strong class="workbench-reference-metric-value max-w-full truncate text-sm leading-none text-slate-900">{{ nestedBlockItemValue(item) }}</strong>
|
|
2106
|
+
<span class="mt-0.5 max-w-full truncate text-xs leading-3 text-slate-500">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
2107
|
+
</div>
|
|
2108
|
+
</div>
|
|
2109
|
+
<div class="workbench-reference-project-quick-links grid h-full min-h-0 grid-cols-2 gap-1 overflow-hidden">
|
|
2110
|
+
<div v-for="(item, index) in referenceQuickLinkItems(effectiveData as CustomCanvasData).slice(0, 4)" :key="`project-quick-${index}`" class="grid h-full min-h-[1.5rem] grid-cols-[minmax(0,1fr)_auto] items-center gap-1 overflow-hidden rounded border border-slate-100 bg-slate-50 px-1.5 py-0 text-xs leading-4">
|
|
2111
|
+
<span class="min-w-0 truncate font-semibold text-slate-800">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
2112
|
+
<span class="text-slate-400">›</span>
|
|
2113
|
+
</div>
|
|
2114
|
+
</div>
|
|
2115
|
+
<div class="workbench-reference-notice-list grid h-full min-h-0 gap-1 overflow-hidden" style="grid-auto-rows: minmax(1.25rem, 1fr);">
|
|
2116
|
+
<div v-for="(item, index) in referenceNoticeItems(effectiveData as CustomCanvasData).slice(0, 2)" :key="`project-notice-${index}`" class="grid h-full min-h-[1.25rem] grid-cols-[minmax(0,1fr)_auto] items-center gap-1.5 overflow-hidden rounded border border-slate-100 bg-slate-50 px-1.5 py-0 text-xs leading-4">
|
|
2117
|
+
<span class="min-w-0 truncate font-semibold text-slate-700">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
2118
|
+
<span :class="nestedBlockPillClasses(item)">{{ nestedBlockItemValue(item) }}</span>
|
|
2119
|
+
</div>
|
|
2120
|
+
</div>
|
|
2121
|
+
</section>
|
|
2122
|
+
</div>
|
|
2123
|
+
<div
|
|
2124
|
+
v-else-if="customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData) === 'healthRadar'"
|
|
2125
|
+
class="workbench-reference-health-radar-panel grid min-h-0 flex-1 grid-cols-[0.95fr_1.05fr] gap-2 overflow-hidden"
|
|
2126
|
+
>
|
|
2127
|
+
<section class="workbench-reference-health-radar-chart grid h-[15rem] min-h-0 grid-rows-[minmax(0,1fr)_auto] gap-1.5 overflow-hidden rounded border border-slate-100 bg-slate-50 px-2 py-2">
|
|
2128
|
+
<svg class="h-full min-h-0 w-full" viewBox="0 0 144 132" aria-label="五维健康雷达图">
|
|
2129
|
+
<polygon points="72,14 125,52 105,114 39,114 19,52" fill="rgba(15,139,141,0.08)" stroke="#cbd5e1" stroke-width="1" />
|
|
2130
|
+
<polygon points="72,38 101,59 90,93 54,93 43,59" fill="rgba(198,133,26,0.08)" stroke="#e2e8f0" stroke-width="1" />
|
|
2131
|
+
<line x1="72" y1="70" x2="72" y2="14" stroke="#d8dee8" />
|
|
2132
|
+
<line x1="72" y1="70" x2="125" y2="52" stroke="#d8dee8" />
|
|
2133
|
+
<line x1="72" y1="70" x2="105" y2="114" stroke="#d8dee8" />
|
|
2134
|
+
<line x1="72" y1="70" x2="39" y2="114" stroke="#d8dee8" />
|
|
2135
|
+
<line x1="72" y1="70" x2="19" y2="52" stroke="#d8dee8" />
|
|
2136
|
+
<polygon :points="referenceHealthRadarPoints(effectiveData as CustomCanvasData)" fill="rgba(199,52,49,0.18)" stroke="#c73431" stroke-width="2.5" stroke-linejoin="round" />
|
|
2137
|
+
<text x="72" y="10" text-anchor="middle" font-size="7" font-weight="700" class="fill-slate-500">经营盈利</text>
|
|
2138
|
+
<text x="132" y="55" text-anchor="end" font-size="7" font-weight="700" class="fill-slate-500">财务资金</text>
|
|
2139
|
+
<text x="110" y="128" text-anchor="middle" font-size="7" font-weight="700" class="fill-slate-500">供应链</text>
|
|
2140
|
+
<text x="34" y="128" text-anchor="middle" font-size="7" font-weight="700" class="fill-slate-500">组织人力</text>
|
|
2141
|
+
<text x="12" y="55" text-anchor="start" font-size="7" font-weight="700" class="fill-slate-500">合规安全</text>
|
|
2142
|
+
</svg>
|
|
2143
|
+
<div class="grid grid-cols-3 gap-1 text-xs">
|
|
2144
|
+
<span class="rounded border border-red-100 bg-red-50 px-1.5 py-1 font-semibold text-red-600">红色维度 2</span>
|
|
2145
|
+
<span class="rounded border border-amber-100 bg-amber-50 px-1.5 py-1 font-semibold text-amber-700">预警维度 3</span>
|
|
2146
|
+
<span class="rounded border border-slate-100 bg-white px-1.5 py-1 font-semibold text-slate-500">健康项弱化</span>
|
|
2147
|
+
</div>
|
|
2148
|
+
</section>
|
|
2149
|
+
<section class="workbench-reference-health-radar-risk-list grid min-h-0 content-start gap-2 overflow-hidden">
|
|
2150
|
+
<div v-for="(item, index) in referenceHealthRadarRiskItems(effectiveData as CustomCanvasData)" :key="`health-risk-${index}`" :class="['workbench-reference-health-risk-card grid h-[7.25rem] min-h-0 grid-rows-[auto_minmax(0,1fr)_auto] rounded border px-3 py-2 text-xs', nestedBlockToneClass(item) === 'critical' ? 'border-red-100 bg-red-50' : 'border-amber-100 bg-amber-50']">
|
|
2151
|
+
<strong class="block truncate text-sm leading-5 text-slate-900" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</strong>
|
|
2152
|
+
<p class="mt-1 max-h-10 self-center overflow-hidden text-sm leading-5 text-slate-600" :title="nestedBlockItemDetail(item)">{{ nestedBlockItemDetail(item) }}</p>
|
|
2153
|
+
<span :class="['mt-1 inline-flex max-w-full truncate', nestedBlockPillClasses(item)]" :title="nestedBlockItemValue(item) || '穿透'">{{ nestedBlockItemValue(item) || '穿透' }}</span>
|
|
2154
|
+
</div>
|
|
2155
|
+
</section>
|
|
2156
|
+
</div>
|
|
2157
|
+
<div
|
|
2158
|
+
v-else-if="customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData) === 'deviation'"
|
|
2159
|
+
class="workbench-reference-deviation-panel grid min-h-0 flex-1 content-start gap-2 overflow-hidden"
|
|
2160
|
+
>
|
|
2161
|
+
<section class="workbench-reference-deviation-chart grid h-[13.5rem] min-h-0 grid-rows-[auto_minmax(0,1fr)_auto] gap-1 overflow-hidden rounded border border-slate-100 bg-slate-50 px-2 py-2">
|
|
2162
|
+
<div class="grid grid-cols-6 gap-1 text-center text-[11px] font-semibold text-slate-400">
|
|
2163
|
+
<span v-for="(item, index) in referenceDeviationBars(effectiveData as CustomCanvasData)" :key="`deviation-target-${index}`" class="truncate" :title="nestedBlockItemValue(item) || '目标'">
|
|
2164
|
+
目标 {{ nestedBlockItemValue(item) }}
|
|
2165
|
+
</span>
|
|
2166
|
+
</div>
|
|
2167
|
+
<div class="relative grid min-h-0 grid-cols-6 items-end gap-1 overflow-hidden px-3">
|
|
2168
|
+
<svg class="pointer-events-none absolute inset-x-2 top-2 h-[54%]" viewBox="0 0 300 72" preserveAspectRatio="none" aria-hidden="true">
|
|
2169
|
+
<path d="M6 58 H294 M6 44 H294 M6 30 H294 M6 16 H294" stroke="#e2e8f0" stroke-width="1" />
|
|
2170
|
+
<polyline points="6,18 64,22 122,42 180,34 238,52 294,62" fill="none" stroke="#c73431" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" />
|
|
2171
|
+
</svg>
|
|
2172
|
+
<div v-for="(item, index) in referenceDeviationBars(effectiveData as CustomCanvasData)" :key="`deviation-bar-${index}`" class="relative z-10 flex h-full min-h-0 items-end justify-center gap-1 text-center text-xs">
|
|
2173
|
+
<i class="block h-[82%] w-3 rounded-t bg-slate-300" />
|
|
2174
|
+
<i :class="['block w-3 rounded-t', nestedBlockToneClass(item) === 'critical' ? 'bg-red-500' : nestedBlockToneClass(item) === 'warning' ? 'bg-amber-500' : 'bg-[#4C78FC]']" :style="{ height: nestedBlockItemProgress(item, 70), minHeight: '36px' }" />
|
|
2175
|
+
</div>
|
|
2176
|
+
</div>
|
|
2177
|
+
<div class="grid grid-cols-6 gap-1 text-center text-xs">
|
|
2178
|
+
<span v-for="(item, index) in referenceDeviationBars(effectiveData as CustomCanvasData)" :key="`deviation-label-${index}`" class="truncate font-semibold text-slate-600" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
2179
|
+
</div>
|
|
2180
|
+
</section>
|
|
2181
|
+
<section class="workbench-reference-deviation-conclusion-band grid min-h-[9.5rem] gap-1.5 overflow-hidden">
|
|
2182
|
+
<div v-for="(item, index) in referenceDeviationRiskItems(effectiveData as CustomCanvasData)" :key="`deviation-risk-${index}`" class="workbench-reference-deviation-conclusion-row grid min-h-[4.5rem] grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-2 rounded border border-red-100 bg-red-50 px-3 py-2 text-xs">
|
|
2183
|
+
<strong class="shrink-0 truncate text-sm leading-5 text-red-700" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</strong>
|
|
2184
|
+
<p class="min-w-0 truncate leading-5 text-red-700/80" :title="nestedBlockItemDetail(item)">{{ nestedBlockItemDetail(item) }}</p>
|
|
2185
|
+
<span class="inline-flex max-w-[6rem] shrink-0 truncate rounded-full border border-red-200 bg-white px-2 py-0.5 font-semibold text-red-600" :title="nestedBlockItemValue(item) || '专项复盘'">{{ nestedBlockItemValue(item) || '专项复盘' }}</span>
|
|
2186
|
+
</div>
|
|
2187
|
+
</section>
|
|
2188
|
+
</div>
|
|
2189
|
+
<div
|
|
2190
|
+
v-else-if="customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData) === 'financeRisk'"
|
|
2191
|
+
class="workbench-reference-finance-risk-panel grid min-h-0 flex-1 grid-rows-[minmax(8rem,0.42fr)_minmax(8rem,0.58fr)] gap-2 overflow-hidden"
|
|
2192
|
+
>
|
|
2193
|
+
<section class="workbench-reference-finance-trend-card grid h-full min-h-0 overflow-hidden rounded border border-slate-100 bg-slate-50 px-2 py-2">
|
|
2194
|
+
<svg class="h-full min-h-0 w-full" viewBox="0 0 280 112" preserveAspectRatio="none" aria-label="资金风险趋势">
|
|
2195
|
+
<line x1="0" y1="34" x2="280" y2="34" stroke="#c73431" stroke-width="2" stroke-dasharray="6 6" />
|
|
2196
|
+
<path d="M0 86 C34 80, 64 76, 92 67 C126 56, 142 40, 170 36 C200 31, 226 24, 280 18 L280 112 L0 112 Z" fill="rgba(199,52,49,0.16)" />
|
|
2197
|
+
<path d="M0 86 C34 80, 64 76, 92 67 C126 56, 142 40, 170 36 C200 31, 226 24, 280 18" fill="none" stroke="#c73431" stroke-width="3" />
|
|
2198
|
+
<path d="M0 96 C42 90, 82 92, 116 82 C150 72, 176 75, 206 63 C238 51, 264 58, 280 48" fill="none" stroke="#d9821b" stroke-width="3" />
|
|
2199
|
+
</svg>
|
|
2200
|
+
</section>
|
|
2201
|
+
<section class="workbench-reference-finance-metric-grid grid h-full min-h-0 grid-cols-3 gap-1.5 overflow-hidden">
|
|
2202
|
+
<div v-for="(item, index) in referenceFinanceRiskBottomItems(effectiveData as CustomCanvasData)" :key="`finance-bottom-${index}`" :class="['grid min-h-0 grid-rows-[auto_minmax(0,1fr)] content-between rounded px-2 py-2 text-xs', nestedBlockToneClass(item) === 'critical' ? 'border border-red-100 bg-red-50' : 'border border-amber-100 bg-amber-50']">
|
|
2203
|
+
<strong :class="['block max-w-full truncate text-[clamp(1.25rem,2.8vw,2.2rem)] leading-tight', nestedBlockToneClass(item) === 'critical' ? 'text-red-700' : 'text-amber-800']" :title="referenceFinanceRiskMetricDisplayValue(item, index) || nestedBlockItemTitle(item, index)">{{ referenceFinanceRiskMetricDisplayValue(item, index) }}</strong>
|
|
2204
|
+
<span :class="['self-end truncate text-xs leading-5', nestedBlockToneClass(item) === 'critical' ? 'text-red-700/80' : 'text-amber-800/80']" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemValue(item) ? nestedBlockItemLabel(item, index) : nestedBlockItemDetail(item) }}</span>
|
|
2205
|
+
</div>
|
|
2206
|
+
</section>
|
|
2207
|
+
</div>
|
|
2208
|
+
<div
|
|
2209
|
+
v-else-if="customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData) === 'expenseRisk'"
|
|
2210
|
+
class="workbench-reference-expense-risk-panel grid min-h-0 flex-1 grid-cols-[1.35fr_0.85fr] gap-2 overflow-hidden"
|
|
2211
|
+
>
|
|
2212
|
+
<section class="workbench-reference-expense-ranking-list grid h-full min-h-0 gap-1.5 overflow-hidden rounded border border-slate-100 bg-slate-50 px-2 py-2" style="grid-auto-rows: minmax(0, 1fr);">
|
|
2213
|
+
<div v-for="(item, index) in referenceExpenseRiskRows(effectiveData as CustomCanvasData)" :key="`expense-row-${index}`" class="grid min-h-0 grid-cols-[4.5rem_minmax(0,1fr)_3.5rem] items-center gap-2 text-xs">
|
|
2214
|
+
<span class="truncate font-semibold text-slate-700" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
2215
|
+
<span class="h-2.5 overflow-hidden rounded-full bg-slate-200"><i :class="nestedBlockBarClasses(item)" :style="nestedBlockBarStyle(item, 52)" /></span>
|
|
2216
|
+
<b class="truncate text-right text-slate-800" :title="nestedBlockItemValue(item)">{{ nestedBlockItemValue(item) }}</b>
|
|
2217
|
+
</div>
|
|
2218
|
+
</section>
|
|
2219
|
+
<section class="workbench-reference-expense-summary-list grid h-full min-h-0 gap-1.5 overflow-hidden" style="grid-auto-rows: minmax(0, 1fr);">
|
|
2220
|
+
<div v-for="(item, index) in referenceExpenseSummaryItems(effectiveData as CustomCanvasData)" :key="`expense-summary-${index}`" class="grid min-h-0 grid-rows-[auto_minmax(0,1fr)_auto] rounded border border-red-100 bg-red-50 px-2 py-2 text-xs">
|
|
2221
|
+
<strong class="block truncate text-sm leading-5 text-red-700" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</strong>
|
|
2222
|
+
<p class="mt-1 self-center truncate leading-5 text-red-700/80" :title="nestedBlockItemDetail(item)">{{ nestedBlockItemDetail(item) }}</p>
|
|
2223
|
+
<span class="mt-1 inline-flex max-w-full truncate rounded-full border border-red-200 bg-white px-2 py-0.5 font-semibold text-red-600" :title="nestedBlockItemValue(item) || '冻结非必要开支'">{{ nestedBlockItemValue(item) || '冻结非必要开支' }}</span>
|
|
2224
|
+
</div>
|
|
2225
|
+
</section>
|
|
2226
|
+
</div>
|
|
2227
|
+
<div
|
|
2228
|
+
v-else-if="customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData) === 'deviationInsight'"
|
|
2229
|
+
class="workbench-reference-deviation-insight-panel grid min-h-0 flex-1 content-start gap-2 overflow-hidden"
|
|
2230
|
+
>
|
|
2231
|
+
<div
|
|
2232
|
+
v-for="(item, index) in referenceDeviationInsightItems(effectiveData as CustomCanvasData)"
|
|
2233
|
+
:key="`deviation-insight-${index}`"
|
|
2234
|
+
class="workbench-reference-deviation-insight-row grid h-12 min-h-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-2 rounded border border-slate-100 bg-slate-50 px-2.5 py-1.5 text-xs"
|
|
2235
|
+
>
|
|
2236
|
+
<span class="min-w-0 truncate leading-5 text-slate-800" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
2237
|
+
<strong :class="['shrink-0 truncate text-sm leading-5', nestedBlockToneClass(item) === 'warning' ? 'text-amber-700' : 'text-slate-900']" :title="nestedBlockItemValue(item)">{{ nestedBlockItemValue(item) }}</strong>
|
|
2238
|
+
</div>
|
|
2239
|
+
</div>
|
|
2240
|
+
<div
|
|
2241
|
+
v-else-if="customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData) === 'organizationRisk'"
|
|
2242
|
+
class="workbench-reference-organization-risk-panel grid min-h-0 flex-1 grid-cols-[0.92fr_1.28fr] gap-2 overflow-hidden"
|
|
2243
|
+
>
|
|
2244
|
+
<section class="workbench-reference-organization-donut grid h-full min-h-0 place-items-center overflow-hidden rounded border border-slate-100 bg-slate-50 px-2 py-2 text-center">
|
|
2245
|
+
<div class="relative grid h-[min(10.5rem,66%)] min-h-[7rem] w-[min(10.5rem,80%)] min-w-[7rem] place-items-center rounded-full" :style="referenceOrganizationDonutStyle(referenceOrganizationRiskMetrics(effectiveData as CustomCanvasData)[0])">
|
|
2246
|
+
<div class="grid h-[58%] w-[58%] place-items-center rounded-full bg-white shadow-sm">
|
|
2247
|
+
<strong class="max-w-full truncate text-[clamp(1.6rem,3.4vw,2.5rem)] leading-none text-slate-900" :title="nestedBlockItemValue(referenceOrganizationRiskMetrics(effectiveData as CustomCanvasData)[0])">{{ nestedBlockItemValue(referenceOrganizationRiskMetrics(effectiveData as CustomCanvasData)[0]) }}</strong>
|
|
2248
|
+
</div>
|
|
2249
|
+
</div>
|
|
2250
|
+
<span class="mt-1 max-w-full truncate text-xs font-semibold text-slate-600" :title="nestedBlockItemTitle(referenceOrganizationRiskMetrics(effectiveData as CustomCanvasData)[0], 0)">{{ nestedBlockItemLabel(referenceOrganizationRiskMetrics(effectiveData as CustomCanvasData)[0], 0) }}</span>
|
|
2251
|
+
</section>
|
|
2252
|
+
<section class="grid min-h-0 content-start gap-1.5 overflow-hidden">
|
|
2253
|
+
<div class="workbench-reference-organization-trend-card grid h-44 min-h-0 grid-rows-[minmax(0,1fr)] rounded border border-slate-100 bg-slate-50 px-2 py-2">
|
|
2254
|
+
<svg class="h-full min-h-0 w-full" viewBox="0 0 280 92" preserveAspectRatio="none" aria-label="人效风险趋势">
|
|
2255
|
+
<path d="M10 88 H270 M10 68 H270 M10 48 H270 M10 28 H270" stroke="#e5e7eb" stroke-width="1" />
|
|
2256
|
+
<path d="M24 78 C58 76, 84 72, 112 65 S166 58, 192 43 S238 28, 264 22" fill="none" stroke="#c73431" stroke-width="4" />
|
|
2257
|
+
<path d="M24 86 C70 84, 102 80, 142 74 S216 64, 264 56" fill="none" stroke="#d9821b" stroke-width="3" stroke-dasharray="6 7" />
|
|
2258
|
+
</svg>
|
|
2259
|
+
</div>
|
|
2260
|
+
<div class="grid grid-cols-3 gap-1.5">
|
|
2261
|
+
<div v-for="(item, index) in referenceOrganizationRiskMetrics(effectiveData as CustomCanvasData).slice(1)" :key="`org-risk-${index}`" class="rounded border border-slate-100 bg-slate-50 px-1.5 py-1 text-center">
|
|
2262
|
+
<strong class="block truncate text-base leading-5 text-red-600" :title="nestedBlockItemValue(item)">{{ nestedBlockItemValue(item) }}</strong>
|
|
2263
|
+
<span class="block truncate text-xs text-slate-500" :title="nestedBlockItemTitle(item, index + 1)">{{ nestedBlockItemLabel(item, index + 1) }}</span>
|
|
2264
|
+
</div>
|
|
2265
|
+
</div>
|
|
2266
|
+
</section>
|
|
2267
|
+
</div>
|
|
2268
|
+
<div
|
|
2269
|
+
v-else-if="customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData) === 'investmentRisk'"
|
|
2270
|
+
class="workbench-reference-investment-risk-panel grid min-h-0 flex-1 grid-cols-[1.35fr_0.78fr] gap-2 overflow-hidden"
|
|
2271
|
+
>
|
|
2272
|
+
<section class="workbench-reference-investment-gantt-grid grid h-full min-h-0 overflow-hidden rounded border border-slate-100 bg-slate-50 px-2 py-2" style="grid-auto-rows: minmax(0, 1fr);">
|
|
2273
|
+
<div v-for="(item, index) in referenceInvestmentRiskRows(effectiveData as CustomCanvasData)" :key="`investment-row-${index}`" class="grid min-h-0 grid-cols-[4.75rem_minmax(0,1fr)_3rem] items-center gap-2 text-xs">
|
|
2274
|
+
<span class="truncate font-semibold text-slate-800" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
2275
|
+
<span class="relative h-4 overflow-hidden rounded bg-slate-200">
|
|
2276
|
+
<i class="absolute inset-y-0 rounded bg-slate-300/80" style="left: 0; right: 0;" />
|
|
2277
|
+
<i :class="['absolute top-0 block h-full rounded', nestedBlockToneClass(item) === 'critical' ? 'bg-red-500' : 'bg-amber-500']" :style="{ left: `${8 + (index % 3) * 8}%`, width: nestedBlockItemProgress(item, 58) }" />
|
|
2278
|
+
</span>
|
|
2279
|
+
<b :class="['truncate text-right', nestedBlockToneClass(item) === 'critical' ? 'text-red-600' : 'text-amber-700']" :title="nestedBlockItemValue(item)">{{ nestedBlockItemValue(item) }}</b>
|
|
2280
|
+
</div>
|
|
2281
|
+
</section>
|
|
2282
|
+
<section class="grid min-h-0 content-start gap-1.5 overflow-hidden">
|
|
2283
|
+
<div v-for="(item, index) in referenceInvestmentSummaryItems(effectiveData as CustomCanvasData)" :key="`investment-summary-${index}`" class="workbench-reference-investment-summary-card grid h-56 min-h-0 grid-rows-[auto_minmax(0,1fr)_auto] rounded border border-amber-100 bg-amber-50 px-2 py-2 text-xs">
|
|
2284
|
+
<strong class="block truncate text-sm leading-5 text-amber-800" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</strong>
|
|
2285
|
+
<p class="mt-1 self-center truncate leading-5 text-amber-800/80" :title="nestedBlockItemDetail(item)">{{ nestedBlockItemDetail(item) }}</p>
|
|
2286
|
+
<span :class="['mt-1 inline-flex max-w-full truncate', nestedBlockPillClasses(item)]" :title="nestedBlockItemValue(item) || '重排里程碑'">{{ nestedBlockItemValue(item) || '重排里程碑' }}</span>
|
|
2287
|
+
</div>
|
|
2288
|
+
<div class="workbench-reference-investment-status-pills grid grid-cols-2 gap-1">
|
|
2289
|
+
<span class="truncate rounded-full border border-red-100 bg-red-50 px-2 py-1 text-center text-xs font-semibold text-red-600">延期 2</span>
|
|
2290
|
+
<span class="truncate rounded-full border border-amber-100 bg-amber-50 px-2 py-1 text-center text-xs font-semibold text-amber-600">超支 2</span>
|
|
2291
|
+
</div>
|
|
2292
|
+
</section>
|
|
2293
|
+
</div>
|
|
2294
|
+
<div
|
|
2295
|
+
v-else-if="customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData) === 'executiveTodo'"
|
|
2296
|
+
class="workbench-reference-executive-todo-panel grid min-h-0 flex-1 content-start gap-2 overflow-hidden"
|
|
2297
|
+
>
|
|
2298
|
+
<div v-for="(item, index) in referenceExecutiveTodoItems(effectiveData as CustomCanvasData, 3)" :key="`executive-todo-${index}`" :class="['grid h-[4.75rem] min-h-0 grid-cols-[minmax(0,1fr)_3.5rem] items-center gap-2 rounded px-3 py-1.5 text-xs workbench-reference-executive-todo-card', nestedBlockToneClass(item) === 'critical' ? 'border border-red-100 bg-red-50' : 'border border-amber-100 bg-amber-50']">
|
|
2299
|
+
<div class="min-w-0">
|
|
2300
|
+
<strong class="block truncate text-sm leading-5 text-slate-900" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</strong>
|
|
2301
|
+
<div class="workbench-reference-executive-todo-detail-grid mt-1.5 grid grid-cols-3 gap-x-2 overflow-hidden text-slate-700">
|
|
2302
|
+
<span class="truncate" :title="referenceExecutiveTodoImpact(item, index)">影响 {{ referenceExecutiveTodoImpact(item, index) }}</span>
|
|
2303
|
+
<span class="truncate" :title="referenceExecutiveTodoDeadline(item, index)">截止 {{ referenceExecutiveTodoDeadline(item, index) }}</span>
|
|
2304
|
+
<span class="truncate" :title="referenceExecutiveTodoProgress(item, index)">进度 {{ referenceExecutiveTodoProgress(item, index) }}</span>
|
|
2305
|
+
</div>
|
|
2306
|
+
</div>
|
|
2307
|
+
<span :class="referenceExecutiveTodoBadgeClasses(item, index)" :title="referenceExecutiveTodoBadge(item, index)">{{ referenceExecutiveTodoBadge(item, index) }}</span>
|
|
2308
|
+
</div>
|
|
2309
|
+
</div>
|
|
2310
|
+
<div
|
|
2311
|
+
v-else-if="customCanvasReferenceCompositeKind(effectiveBlock, effectiveData as CustomCanvasData) === 'shortcutDrill'"
|
|
2312
|
+
class="workbench-reference-shortcut-drill-panel grid min-h-0 flex-1 grid-cols-3 content-start gap-1.5 overflow-hidden"
|
|
2313
|
+
>
|
|
2314
|
+
<div v-for="(item, index) in referenceShortcutDrillItems(effectiveData as CustomCanvasData)" :key="`shortcut-drill-${index}`" class="grid min-h-[52px] min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-2 rounded border border-slate-100 bg-slate-50 px-2 py-1.5 text-xs">
|
|
2315
|
+
<span class="min-w-0 truncate font-semibold text-slate-800" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
2316
|
+
<span :class="['max-w-[4rem] truncate', nestedBlockPillClasses(item)]" :title="nestedBlockItemValue(item) || '›'">{{ nestedBlockItemValue(item) || '›' }}</span>
|
|
2317
|
+
</div>
|
|
2318
|
+
</div>
|
|
2319
|
+
</div>
|
|
2320
|
+
<div
|
|
2321
|
+
v-else-if="customCanvasStandaloneQuickLinks(effectiveBlock, effectiveData as CustomCanvasData)"
|
|
2322
|
+
class="workbench-custom-canvas-quick-links absolute inset-0 flex min-h-0 w-full items-center gap-2 overflow-hidden border-y border-[#d9e2ec] bg-[#f7fafc] px-4 py-0"
|
|
2323
|
+
>
|
|
2324
|
+
<div class="flex h-full w-[64px] shrink-0 items-center overflow-hidden">
|
|
2325
|
+
<span class="truncate text-sm font-semibold leading-5 text-slate-600">{{ '\u5feb\u6377\u5165\u53e3' }}</span>
|
|
2326
|
+
</div>
|
|
2327
|
+
<div class="flex min-h-0 min-w-0 flex-1 items-center gap-3 overflow-hidden">
|
|
2328
|
+
<div
|
|
2329
|
+
v-for="(item, index) in customCanvasStandaloneQuickLinkItems(effectiveBlock, effectiveData as CustomCanvasData)"
|
|
2330
|
+
:key="`custom-quick-${index}-${nestedBlockItemLabel(item, index)}`"
|
|
2331
|
+
class="flex h-7 min-w-[78px] max-w-[104px] shrink-0 items-center justify-center overflow-hidden rounded border border-[#cfdbe7] bg-white px-3 text-xs"
|
|
2332
|
+
:title="nestedBlockItemTitle(item, index)"
|
|
2333
|
+
>
|
|
2334
|
+
<span class="min-w-0 truncate font-semibold text-[#17243a]">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
2335
|
+
</div>
|
|
2336
|
+
</div>
|
|
2337
|
+
</div>
|
|
2338
|
+
<div
|
|
2339
|
+
v-else-if="customCanvasVisibleNestedBlocks(effectiveData as CustomCanvasData).length"
|
|
2340
|
+
:class="customCanvasNestedBlockContainerClasses(effectiveBlock, effectiveData as CustomCanvasData)"
|
|
2341
|
+
:style="customCanvasNestedStackContainerStyle(effectiveData as CustomCanvasData)"
|
|
2342
|
+
>
|
|
2343
|
+
<button
|
|
2344
|
+
v-for="nestedBlock in customCanvasVisibleNestedBlocks(effectiveData as CustomCanvasData)"
|
|
2345
|
+
:key="nestedBlock.id"
|
|
2346
|
+
type="button"
|
|
2347
|
+
data-testid="workbench-nested-card-preview"
|
|
2348
|
+
:data-parent-block-id="effectiveBlock.id"
|
|
2349
|
+
:data-nested-block-id="nestedBlock.id"
|
|
2350
|
+
:data-nested-card-id="nestedBlock.id"
|
|
2351
|
+
:data-nested-card-title="nestedBlock.title"
|
|
2352
|
+
:data-nested-card-kind="nestedBlock.kind"
|
|
2353
|
+
:data-capability-id="nestedBlock.capabilityId"
|
|
2354
|
+
:data-compose-source="nestedBlockComposeSource(nestedBlock)"
|
|
2355
|
+
:data-binding-id="nestedBlock.dataBindingId || nestedBlock.dataBinding?.bindingId || nestedBlock.dataBinding?.id || ''"
|
|
2356
|
+
:data-binding-status="nestedBlock.dataBindingStatus"
|
|
2357
|
+
:data-renderer-key="nestedBlockRendererKey(nestedBlock)"
|
|
2358
|
+
:data-data-shape="nestedBlock.dataShape"
|
|
2359
|
+
:data-visual-kind="nestedBlockVisualKind(nestedBlock)"
|
|
2360
|
+
:data-business-gap="nestedBlockNeedsHumanIntervention(nestedBlock) ? 'true' : undefined"
|
|
2361
|
+
:data-business-gap-reason="nestedBlockNeedsHumanIntervention(nestedBlock) ? nestedBlockBusinessGapReason(nestedBlock) : undefined"
|
|
2362
|
+
:data-business-gap-diagnostics="nestedBlockNeedsHumanIntervention(nestedBlock) ? nestedBlockFailureReason(nestedBlock) : undefined"
|
|
2363
|
+
:class="nestedBlockShellClasses(nestedBlock, customCanvasUsesAbsoluteNestedBlocks(effectiveBlock, effectiveData as CustomCanvasData), customCanvasDenseNestedStack(effectiveData as CustomCanvasData), customCanvasUsesNaturalNestedGrid(effectiveData as CustomCanvasData) && !customCanvasShouldFillNaturalNestedGrid(effectiveBlock, effectiveData as CustomCanvasData))"
|
|
2364
|
+
:style="{
|
|
2365
|
+
...nestedBlockCanvasStyle(nestedBlock, effectiveData as CustomCanvasData, customCanvasUsesAbsoluteNestedBlocks(effectiveBlock, effectiveData as CustomCanvasData)),
|
|
2366
|
+
...nestedBlockStackTailPlacementStyle(nestedBlock, effectiveData as CustomCanvasData),
|
|
2367
|
+
...nestedBlockGridPlacementStyle(nestedBlock, effectiveData as CustomCanvasData, customCanvasUsesAbsoluteNestedBlocks(effectiveBlock, effectiveData as CustomCanvasData)),
|
|
2368
|
+
}"
|
|
2369
|
+
:title="nestedBlockFocusTitle(nestedBlock)"
|
|
2370
|
+
:aria-label="nestedBlockFocusTitle(nestedBlock)"
|
|
2371
|
+
@pointerdown.stop
|
|
2372
|
+
@click.stop="focusNestedBlock(nestedBlock)"
|
|
2373
|
+
>
|
|
2374
|
+
<div class="flex min-w-0 items-start justify-between gap-2">
|
|
2375
|
+
<div class="min-w-0">
|
|
2376
|
+
<div class="truncate text-xs font-semibold text-slate-900">{{ nestedBlock.title }}</div>
|
|
2377
|
+
<div v-if="customCanvasShowsStructureLabels(effectiveBlock)" class="mt-1 truncate text-[11px] text-slate-500">{{ nestedBlock.slot }} · {{ nestedBlock.kind }}</div>
|
|
2378
|
+
</div>
|
|
2379
|
+
<span
|
|
2380
|
+
v-if="nestedBlockNeedsHumanIntervention(nestedBlock)"
|
|
2381
|
+
class="workbench-nested-business-gap-dot workbench-nested-card-role-badge shrink-0 rounded border border-amber-200 bg-amber-50 px-1.5 py-0 text-[12px] font-semibold leading-4 text-amber-700"
|
|
2382
|
+
data-nested-business-gap-action-label="true"
|
|
2383
|
+
:title="nestedBlockFailureReason(nestedBlock)"
|
|
2384
|
+
aria-label="需补充业务口径"
|
|
2385
|
+
>
|
|
2386
|
+
子卡 · 补口径
|
|
2387
|
+
</span>
|
|
2388
|
+
<span v-if="!nestedBlockNeedsHumanIntervention(nestedBlock) && !nestedBlockEmptyImageContainer(nestedBlock)" :class="['workbench-nested-card-role-badge shrink-0 rounded border border-slate-200 bg-slate-50 text-xs font-medium text-slate-500', nestedBlockCompactPreview(nestedBlock) ? 'px-1.5 py-0' : 'px-2 py-0.5']">
|
|
2389
|
+
子卡
|
|
2390
|
+
</span>
|
|
2391
|
+
</div>
|
|
2392
|
+
<div v-if="nestedBlock.dataBindingStatus === 'error' && !nestedBlockDataSnapshotRenderable(nestedBlock) && !nestedBlockNeedsHumanIntervention(nestedBlock)" class="mt-2 rounded border border-rose-100 bg-rose-50 px-2 py-1 text-[11px] leading-5 text-rose-700">
|
|
2393
|
+
<div v-if="nestedBlockNeedsHumanIntervention(nestedBlock)" class="mb-1 font-semibold text-amber-700">需补充业务口径</div>
|
|
2394
|
+
<div class="line-clamp-2 font-medium" :title="nestedBlockFailureReason(nestedBlock)">{{ nestedBlockFailureReason(nestedBlock) }}</div>
|
|
2395
|
+
<div class="mt-0.5 line-clamp-1 text-rose-600" :title="nestedBlockQueryIntent(nestedBlock)">{{ nestedBlockQueryIntent(nestedBlock) }}</div>
|
|
2396
|
+
</div>
|
|
2397
|
+
<div v-else-if="nestedBlockEmptyImageContainer(nestedBlock)" class="mt-1 grid min-h-0 flex-1 grid-cols-[minmax(0,1fr)_auto] items-center gap-2 overflow-hidden rounded border border-slate-100 bg-slate-50 px-2 py-1 text-xs">
|
|
2398
|
+
<span class="min-w-0 truncate text-slate-500">保留截图区域,等待可用业务口径</span>
|
|
2399
|
+
<span class="shrink-0 rounded-full border border-slate-200 bg-white px-1.5 py-0.5 font-semibold leading-4 text-slate-500">待回填</span>
|
|
2400
|
+
</div>
|
|
2401
|
+
<div v-else-if="nestedBlockVisualKind(nestedBlock) === 'statusList'" class="workbench-nested-status-list mt-1 grid min-h-0 flex-1 auto-rows-fr gap-1 overflow-hidden">
|
|
2402
|
+
<div class="workbench-nested-status-summary grid grid-cols-3 gap-1">
|
|
2403
|
+
<div v-for="item in nestedBlockStatusSummary(nestedBlock)" :key="`${nestedBlock.id}-status-summary-${item.tone}`" class="min-w-0 rounded border border-slate-100 bg-slate-50 px-1.5 py-1 text-center">
|
|
2404
|
+
<strong class="block text-sm leading-4 text-slate-900">{{ item.count }}</strong>
|
|
2405
|
+
<span class="block truncate text-[11px] leading-4 text-slate-500">{{ nestedBlockStatusSummaryLabel(item.tone) }}</span>
|
|
2406
|
+
</div>
|
|
2407
|
+
</div>
|
|
2408
|
+
<div v-for="(item, index) in nestedBlockItems(nestedBlock).slice(0, 4)" :key="`${nestedBlock.id}-status-${index}`" class="grid min-h-0 grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-1.5 rounded border border-slate-100 bg-white px-2 py-1 text-xs">
|
|
2409
|
+
<i :class="nestedBlockDotClasses(item)" />
|
|
2410
|
+
<span class="min-w-0 truncate font-semibold text-slate-800">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
2411
|
+
<span :class="nestedBlockPillClasses(item)">{{ nestedBlockItemValue(item) || '正常' }}</span>
|
|
2412
|
+
</div>
|
|
2413
|
+
</div>
|
|
2414
|
+
<div v-else-if="nestedBlockVisualKind(nestedBlock) === 'incidentList'" class="workbench-nested-incident-list workbench-nested-incident-timeline mt-1 grid min-h-0 flex-1 auto-rows-fr gap-1 overflow-hidden">
|
|
2415
|
+
<div v-for="(item, index) in nestedBlockItems(nestedBlock).slice(0, 3)" :key="`${nestedBlock.id}-incident-${index}`" class="grid min-h-0 grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-1.5 rounded border border-slate-100 bg-white px-2 py-1 text-xs">
|
|
2416
|
+
<span class="grid place-items-center gap-0.5">
|
|
2417
|
+
<i :class="nestedBlockDotClasses(item)" />
|
|
2418
|
+
<span :class="nestedBlockPillClasses(item)">{{ nestedBlockItemSeverity(item) }}</span>
|
|
2419
|
+
</span>
|
|
2420
|
+
<span class="min-w-0">
|
|
2421
|
+
<strong class="block truncate text-xs leading-4 text-slate-800">{{ nestedBlockItemLabel(item, index) }}</strong>
|
|
2422
|
+
<span class="block truncate text-xs leading-4 text-slate-500">{{ nestedBlockItemDetail(item) }}</span>
|
|
2423
|
+
</span>
|
|
2424
|
+
<span class="shrink-0 text-xs font-medium text-slate-500">{{ nestedBlockItemTime(item) }}</span>
|
|
2425
|
+
</div>
|
|
2426
|
+
</div>
|
|
2427
|
+
<div v-else-if="nestedBlockVisualKind(nestedBlock) === 'resourceBars'" class="workbench-nested-resource-bars mt-2 grid min-h-0 flex-1 auto-rows-fr gap-2 overflow-hidden">
|
|
2428
|
+
<div v-for="(item, index) in nestedBlockBarItems(nestedBlock)" :key="`${nestedBlock.id}-resource-${index}`" class="grid grid-cols-[3.5rem_minmax(0,1fr)_2.5rem] items-center gap-2 text-xs">
|
|
2429
|
+
<span class="truncate text-slate-500">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
2430
|
+
<span class="grid gap-0.5">
|
|
2431
|
+
<span class="h-3 overflow-hidden rounded-full bg-slate-200"><i :class="nestedBlockBarClasses(item)" :style="nestedBlockBarStyle(item, 60)" /></span>
|
|
2432
|
+
<span class="workbench-nested-resource-threshold grid grid-cols-3 text-xs leading-3 text-slate-400">
|
|
2433
|
+
<i>0</i><i class="text-center">70</i><i class="text-right">100</i>
|
|
2434
|
+
</span>
|
|
2435
|
+
</span>
|
|
2436
|
+
<b class="text-right font-semibold text-slate-600">{{ nestedBlockItemValue(item) || nestedBlockItemProgress(item) }}</b>
|
|
2437
|
+
</div>
|
|
2438
|
+
</div>
|
|
2439
|
+
<div v-else-if="nestedBlockVisualKind(nestedBlock) === 'securityScore'" class="workbench-nested-security-score mt-1 rounded-md bg-[#101820] p-2 text-white">
|
|
2440
|
+
<div class="flex items-center justify-between gap-2">
|
|
2441
|
+
<span class="truncate text-xs text-slate-300">安全健康分</span>
|
|
2442
|
+
<span class="rounded-full border border-amber-200 bg-amber-50 px-2 py-0.5 text-xs font-semibold text-amber-700">中风险</span>
|
|
2443
|
+
</div>
|
|
2444
|
+
<div class="mt-2 grid grid-cols-[minmax(0,1fr)_4rem] items-center gap-2">
|
|
2445
|
+
<div class="min-w-0">
|
|
2446
|
+
<strong class="text-3xl leading-none">{{ nestedBlockSecurityScore(nestedBlock) }}</strong>
|
|
2447
|
+
<span class="ml-1 text-xs text-slate-300">/ 100</span>
|
|
2448
|
+
<div class="workbench-nested-security-track mt-2 h-1.5 overflow-hidden rounded-full bg-slate-700">
|
|
2449
|
+
<i class="block h-full rounded-full bg-emerald-500" :style="{ width: nestedBlockPercent(nestedBlockSecurityScore(nestedBlock), 86) }" />
|
|
2450
|
+
</div>
|
|
2451
|
+
</div>
|
|
2452
|
+
<div class="grid h-14 w-14 place-items-center rounded-full text-sm font-bold shadow-inner" style="background: radial-gradient(circle at center, #101820 0 54%, transparent 55%), conic-gradient(#15875a 0 62%, #bf811d 62% 86%, #334155 86% 100%);">{{ nestedBlockSecurityScoreRingLabel(nestedBlock) }}</div>
|
|
2453
|
+
</div>
|
|
2454
|
+
<div class="mt-2 grid grid-cols-3 gap-1">
|
|
2455
|
+
<div v-for="(item, index) in nestedBlockSecurityMetrics(nestedBlock)" :key="`${nestedBlock.id}-security-${index}`" class="min-w-0 rounded border border-slate-700 bg-slate-800 px-1.5 py-1">
|
|
2456
|
+
<strong class="block truncate text-sm leading-4">{{ nestedBlockItemValue(item) || nestedBlockItemLabel(item, index) }}</strong>
|
|
2457
|
+
<span class="block truncate text-xs leading-4 text-slate-400">{{ nestedBlockItemValue(item) ? nestedBlockItemLabel(item, index) : '' }}</span>
|
|
2458
|
+
</div>
|
|
2459
|
+
</div>
|
|
2460
|
+
</div>
|
|
2461
|
+
<div v-else-if="nestedBlockVisualKind(nestedBlock) === 'simpleList'" class="workbench-nested-simple-list mt-1 grid min-h-0 flex-1 auto-rows-fr gap-1 overflow-hidden">
|
|
2462
|
+
<div v-for="(item, index) in nestedBlockItems(nestedBlock).slice(0, 5)" :key="`${nestedBlock.id}-simple-${index}`" class="grid min-h-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-2 rounded border border-slate-100 bg-slate-50 px-2 py-1 text-xs">
|
|
2463
|
+
<span class="min-w-0 truncate font-semibold text-slate-800">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
2464
|
+
<span :class="nestedBlockPillClasses(item)">{{ nestedBlockItemValue(item) || '待确认' }}</span>
|
|
2465
|
+
</div>
|
|
2466
|
+
</div>
|
|
2467
|
+
<div v-else-if="nestedBlockVisualKind(nestedBlock) === 'progressList'" class="workbench-nested-progress-list mt-1 grid min-h-0 flex-1 auto-rows-fr gap-1.5 overflow-hidden">
|
|
2468
|
+
<div v-for="(item, index) in nestedBlockBarItems(nestedBlock)" :key="`${nestedBlock.id}-progress-${index}`" class="grid min-h-0 grid-cols-[minmax(0,1fr)_5rem] gap-1.5 rounded border border-slate-100 bg-white px-2 py-1.5 text-xs">
|
|
2469
|
+
<div class="min-w-0">
|
|
2470
|
+
<div class="grid grid-cols-[minmax(0,1fr)_auto] items-center gap-2">
|
|
2471
|
+
<span class="min-w-0 truncate font-semibold text-slate-800">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
2472
|
+
<span class="workbench-nested-progress-stage shrink-0 text-[11px] text-slate-500">{{ nestedBlockProgressStage(item, index) }}</span>
|
|
2473
|
+
</div>
|
|
2474
|
+
<span class="mt-1 block h-2 overflow-hidden rounded-full bg-slate-200"><i :class="nestedBlockBarClasses(item)" :style="nestedBlockBarStyle(item, 52)" /></span>
|
|
2475
|
+
</div>
|
|
2476
|
+
<span :class="nestedBlockPillClasses(item)">{{ nestedBlockItemValue(item) || nestedBlockItemProgress(item) }}</span>
|
|
2477
|
+
</div>
|
|
2478
|
+
</div>
|
|
2479
|
+
<div v-else-if="nestedBlockVisualKind(nestedBlock) === 'todoGrid'" class="workbench-nested-todo-grid mt-1 grid min-h-0 flex-1 grid-cols-2 gap-1.5 overflow-hidden">
|
|
2480
|
+
<div v-for="(item, index) in nestedBlockTileItems(nestedBlock)" :key="`${nestedBlock.id}-todo-${index}`" class="relative grid min-h-[54px] place-items-center rounded border border-slate-100 bg-white px-2 py-1 text-center">
|
|
2481
|
+
<span class="workbench-nested-todo-corner absolute right-1 top-1 rounded bg-slate-100 px-1 text-xs leading-4 text-slate-500">{{ index + 1 }}</span>
|
|
2482
|
+
<strong class="text-xl leading-none text-slate-900">{{ nestedBlockItemValue(item) || nestedBlockItemLabel(item, index) }}</strong>
|
|
2483
|
+
<span class="mt-1 max-w-full truncate text-xs text-slate-500">{{ nestedBlockItemValue(item) ? nestedBlockItemLabel(item, index) : '' }}</span>
|
|
2484
|
+
</div>
|
|
2485
|
+
</div>
|
|
2486
|
+
<div v-else-if="nestedBlockVisualKind(nestedBlock) === 'quickLinks'" class="workbench-nested-quick-links mt-1 grid min-h-0 flex-1 content-start gap-1.5 overflow-hidden" :style="nestedBlockQuickLinksGridStyle(nestedBlock)">
|
|
2487
|
+
<div v-for="(item, index) in nestedBlockTileItems(nestedBlock)" :key="`${nestedBlock.id}-quick-${index}`" class="grid min-h-0 grid-cols-[auto_minmax(0,1fr)] items-center gap-1.5 rounded border border-slate-100 bg-white px-2 py-1.5 text-xs">
|
|
2488
|
+
<span class="workbench-nested-quick-icon grid h-6 w-6 shrink-0 place-items-center rounded bg-[#edf3ff] text-xs font-semibold text-[#1f4fd4]">{{ nestedBlockQuickIconLabel(item, index) }}</span>
|
|
2489
|
+
<span class="workbench-nested-quick-label min-w-0 break-words font-semibold leading-4 text-slate-800">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
2490
|
+
</div>
|
|
2491
|
+
</div>
|
|
2492
|
+
<div v-else-if="nestedBlockVisualKind(nestedBlock) === 'donut'" class="workbench-nested-donut mt-1 grid grid-cols-[4.5rem_minmax(0,1fr)] items-center gap-2 overflow-hidden rounded border border-slate-100 bg-slate-50 p-2">
|
|
2493
|
+
<div class="grid h-16 w-16 place-items-center rounded-full text-xs font-semibold text-slate-500" :style="nestedBlockDonutStyle(nestedBlock)">年度预算</div>
|
|
2494
|
+
<div class="grid min-w-0 gap-1 text-xs">
|
|
2495
|
+
<div v-for="(item, index) in nestedBlockDonutItems(nestedBlock)" :key="`${nestedBlock.id}-donut-${index}`" class="grid grid-cols-[minmax(0,1fr)_auto] gap-1">
|
|
2496
|
+
<span class="truncate text-slate-500">{{ nestedBlockItemLabel(item, index) }}</span>
|
|
2497
|
+
<b class="text-slate-800">{{ nestedBlockItemValue(item) }}</b>
|
|
2498
|
+
</div>
|
|
2499
|
+
</div>
|
|
2500
|
+
</div>
|
|
2501
|
+
<div v-else-if="nestedBlockVisualKind(nestedBlock) === 'metric'" :class="nestedBlockCompactPreview(nestedBlock) ? 'mt-1' : 'mt-2'">
|
|
2502
|
+
<div :class="['font-semibold leading-none text-slate-950', nestedBlockCompactPreview(nestedBlock) ? 'text-lg' : 'text-xl']" :style="nestedBlockAccentStyle(nestedBlock)">{{ nestedBlockMetricValue(nestedBlock) }}</div>
|
|
2503
|
+
<div v-if="!nestedBlockCompactPreview(nestedBlock)" class="mt-1 truncate text-[11px] text-slate-500">{{ nestedBlockDataSummary(nestedBlock) }}</div>
|
|
2504
|
+
</div>
|
|
2505
|
+
<div v-else-if="nestedBlockVisualKind(nestedBlock) === 'table'" :class="['overflow-hidden rounded border border-slate-100', nestedBlockCompactPreview(nestedBlock) ? 'mt-1' : 'mt-2']">
|
|
2506
|
+
<div class="grid bg-slate-50" :style="rowGrid(nestedBlockColumns(nestedBlock))">
|
|
2507
|
+
<div v-for="column in nestedBlockColumns(nestedBlock)" :key="column" :class="['truncate border-b border-slate-100 px-2 text-xs font-semibold text-slate-500', nestedBlockCompactPreview(nestedBlock) ? 'py-0.5' : 'py-1']">{{ column }}</div>
|
|
2508
|
+
</div>
|
|
2509
|
+
<div v-for="row in nestedBlockRows(nestedBlock).slice(0, 2)" :key="JSON.stringify(row)" class="grid" :style="rowGrid(nestedBlockColumns(nestedBlock))">
|
|
2510
|
+
<div v-for="column in nestedBlockColumns(nestedBlock)" :key="column" :class="['truncate px-2 text-xs text-slate-700', nestedBlockCompactPreview(nestedBlock) ? 'py-0.5' : 'py-1']">{{ nestedBlockCell(row, column) }}</div>
|
|
2511
|
+
</div>
|
|
2512
|
+
</div>
|
|
2513
|
+
<div v-else-if="nestedBlockVisualKind(nestedBlock) === 'list'" :class="nestedBlockCompactPreview(nestedBlock) ? 'mt-1 space-y-0.5' : 'mt-2 space-y-1'">
|
|
2514
|
+
<div v-for="(item, index) in nestedBlockRankingItems(nestedBlock)" :key="`${nestedBlock.id}-${index}`" class="flex items-center justify-between gap-2 text-xs">
|
|
2515
|
+
<span class="min-w-0 truncate text-slate-600">{{ textValue(item.label, textValue(item.name, textValue(item.title, String(index + 1)))) }}</span>
|
|
2516
|
+
<span class="shrink-0 font-semibold text-slate-900">{{ textValue(item.value, textValue(item.amount, '')) }}</span>
|
|
2517
|
+
</div>
|
|
2518
|
+
</div>
|
|
2519
|
+
<div v-else-if="nestedBlockVisualKind(nestedBlock) === 'chart'" :class="['flex min-h-[48px] flex-1 items-end gap-1 rounded border border-slate-100 bg-slate-50 px-2', nestedBlockCompactPreview(nestedBlock) ? 'mt-1 py-1.5' : 'mt-2 py-2']">
|
|
2520
|
+
<div v-for="index in 8" :key="index" class="min-w-0 flex-1 rounded-sm bg-[#4C78FC]/70" :style="{ ...nestedBlockAccentStyle(nestedBlock), backgroundColor: nestedBlock.visual?.accentColor || undefined, height: nestedBlockCompactPreview(nestedBlock) ? `${10 + ((index * 13) % 24)}px` : `${18 + ((index * 17) % 36)}px` }" />
|
|
2521
|
+
</div>
|
|
2522
|
+
<div v-else :class="['truncate text-xs text-slate-500', nestedBlockCompactPreview(nestedBlock) ? 'mt-1' : 'mt-2']">{{ nestedBlockDataSummary(nestedBlock) }}</div>
|
|
2523
|
+
</button>
|
|
2524
|
+
</div>
|
|
2525
|
+
<div
|
|
2526
|
+
v-else-if="customCanvasEmptyImagePlaceholder(effectiveBlock, effectiveData as CustomCanvasData)"
|
|
2527
|
+
class="workbench-custom-canvas-empty-placeholder grid h-full min-h-0 w-full grid-cols-[minmax(0,1fr)_auto] items-center gap-2 overflow-hidden rounded-md border border-slate-200 bg-slate-50 px-3 py-1 text-xs"
|
|
2528
|
+
>
|
|
2529
|
+
<div class="min-w-0">
|
|
2530
|
+
<span class="block truncate text-slate-500">保留截图区域,等待可用业务口径</span>
|
|
2531
|
+
</div>
|
|
2532
|
+
<span class="shrink-0 rounded-full border border-slate-200 bg-white px-2 py-0.5 font-semibold leading-5 text-slate-500">待回填</span>
|
|
2533
|
+
</div>
|
|
2534
|
+
<div v-if="customCanvasOverlaysVisibleElements(effectiveBlock, effectiveData as CustomCanvasData)" class="pointer-events-none absolute inset-0 overflow-hidden">
|
|
2535
|
+
<template v-for="element in customCanvasVisibleElements(effectiveBlock, effectiveData as CustomCanvasData)" :key="element.id">
|
|
2536
|
+
<div
|
|
2537
|
+
v-if="element.kind === 'divider'"
|
|
2538
|
+
:class="customCanvasElementClasses(element)"
|
|
2539
|
+
:style="customCanvasElementStyle(element)"
|
|
2540
|
+
/>
|
|
2541
|
+
<div
|
|
2542
|
+
v-else
|
|
2543
|
+
:class="customCanvasElementClasses(element)"
|
|
2544
|
+
:style="customCanvasElementStyle(element)"
|
|
2545
|
+
:title="element.label || element.value"
|
|
2546
|
+
>
|
|
2547
|
+
<template v-if="element.kind === 'metric'">
|
|
2548
|
+
<span class="block truncate text-xs opacity-75">{{ element.label }}</span>
|
|
2549
|
+
<span class="block truncate text-lg font-semibold leading-6">{{ element.value }}</span>
|
|
2550
|
+
</template>
|
|
2551
|
+
<template v-else>{{ element.label || element.value }}</template>
|
|
2552
|
+
</div>
|
|
2553
|
+
</template>
|
|
2554
|
+
</div>
|
|
2555
|
+
<template v-else>
|
|
2556
|
+
<template v-for="element in customCanvasVisibleElements(effectiveBlock, effectiveData as CustomCanvasData)" :key="element.id">
|
|
2557
|
+
<span v-if="element.kind === 'badge'" class="inline-flex rounded-full bg-white px-2.5 py-1 text-xs text-slate-600">{{ element.label }}{{ element.value ? ` · ${element.value}` : '' }}</span>
|
|
2558
|
+
<div v-else-if="element.kind === 'divider'" class="h-px bg-slate-200" />
|
|
2559
|
+
<div v-else-if="element.kind === 'metric'"><div class="text-xs text-slate-500">{{ element.label }}</div><div class="text-2xl font-semibold text-slate-900">{{ element.value }}</div></div>
|
|
2560
|
+
<div v-else class="text-sm leading-6 text-slate-700">{{ element.label || element.value }}</div>
|
|
2561
|
+
</template>
|
|
2562
|
+
</template>
|
|
2563
|
+
<div v-if="!customCanvasOverlaysVisibleElements(effectiveBlock, effectiveData as CustomCanvasData) && customCanvasVisibleNarrative(effectiveBlock, effectiveData as CustomCanvasData)" class="text-xs text-slate-500">{{ customCanvasVisibleNarrative(effectiveBlock, effectiveData as CustomCanvasData) }}</div>
|
|
2564
|
+
</div>
|
|
2565
|
+
</template>
|
|
2566
|
+
|
|
2567
|
+
<template v-else-if="manualReplacementView(effectiveBlock)">
|
|
2568
|
+
<div :class="manualReplacementShellClasses(effectiveBlock)" :style="manualReplacementContainerStyle(effectiveBlock)">
|
|
2569
|
+
<div class="min-h-0 flex-1 space-y-1 overflow-y-auto pr-1">
|
|
2570
|
+
<div class="min-w-0 space-y-1">
|
|
2571
|
+
<div class="inline-flex rounded-full bg-white px-2.5 py-0.5 text-xs font-semibold text-amber-700">需手动替换</div>
|
|
2572
|
+
<div class="truncate text-sm font-semibold leading-5 text-slate-900" :title="effectiveBlock.title || '未识别区域'">{{ effectiveBlock.title || '未识别区域' }}</div>
|
|
2573
|
+
<p class="line-clamp-1 text-xs leading-5 text-amber-800" :title="manualReplacementView(effectiveBlock)?.reason">{{ manualReplacementView(effectiveBlock)?.reason }}</p>
|
|
2574
|
+
<p v-if="manualReplacementCompactView(effectiveBlock)" class="truncate text-xs font-medium text-amber-700" :title="manualReplacementView(effectiveBlock)?.suggestedCapabilityLabel || manualReplacementView(effectiveBlock)?.suggestedKindLabel">
|
|
2575
|
+
{{ manualReplacementView(effectiveBlock)?.suggestedCapabilityLabel || manualReplacementView(effectiveBlock)?.suggestedKindLabel }}
|
|
2576
|
+
</p>
|
|
2577
|
+
</div>
|
|
2578
|
+
<div v-if="!manualReplacementCompactView(effectiveBlock)" class="grid gap-1 text-xs text-slate-600" style="grid-template-columns: repeat(auto-fit, minmax(92px, 1fr));">
|
|
2579
|
+
<div class="min-w-0 rounded-md bg-white px-2 py-1">
|
|
2580
|
+
<div class="text-slate-400">建议类型</div>
|
|
2581
|
+
<div class="mt-0.5 font-semibold text-slate-800">{{ manualReplacementView(effectiveBlock)?.suggestedKindLabel }}</div>
|
|
2582
|
+
<div v-if="manualReplacementView(effectiveBlock)?.suggestedCapabilityLabel" class="mt-0.5 truncate text-xs font-medium text-amber-700" :title="manualReplacementView(effectiveBlock)?.suggestedCapabilityLabel">{{ manualReplacementView(effectiveBlock)?.suggestedCapabilityLabel }}</div>
|
|
2583
|
+
</div>
|
|
2584
|
+
<div class="min-w-0 rounded-md bg-white px-2 py-1">
|
|
2585
|
+
<div class="text-slate-400">置信度</div>
|
|
2586
|
+
<div class="mt-0.5 font-semibold text-slate-800">{{ manualReplacementView(effectiveBlock)?.confidenceLabel }}</div>
|
|
2587
|
+
</div>
|
|
2588
|
+
<div class="min-w-0 rounded-md bg-white px-2 py-1">
|
|
2589
|
+
<div class="text-slate-400">截图区域</div>
|
|
2590
|
+
<div class="mt-0.5 truncate font-semibold text-slate-800">{{ manualReplacementView(effectiveBlock)?.regionLabel }}</div>
|
|
2591
|
+
</div>
|
|
2592
|
+
</div>
|
|
2593
|
+
</div>
|
|
2594
|
+
<div class="grid shrink-0 min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-1 border-t border-amber-100 pt-1">
|
|
2595
|
+
<label v-if="!manualReplacementCompactView(effectiveBlock)" class="min-w-0 text-xs font-medium text-amber-900">
|
|
2596
|
+
<span class="sr-only">替换卡片</span>
|
|
2597
|
+
<select
|
|
2598
|
+
class="h-6 w-full rounded-md border border-amber-200 bg-white px-2 text-xs text-slate-800 outline-none transition focus:border-[#4C78FC] focus:ring-2 focus:ring-blue-100"
|
|
2599
|
+
:value="manualReplacementCapabilityDraft(effectiveBlock)"
|
|
2600
|
+
:title="manualReplacementCapabilityDraftLabel(effectiveBlock)"
|
|
2601
|
+
@change="setManualReplacementCapabilityDraft(effectiveBlock.id, ($event.target as HTMLSelectElement).value)"
|
|
2602
|
+
>
|
|
2603
|
+
<option
|
|
2604
|
+
v-for="option in manualReplacementCapabilityOptionsForBlock(effectiveBlock)"
|
|
2605
|
+
:key="option.capabilityId"
|
|
2606
|
+
:value="option.capabilityId"
|
|
2607
|
+
>
|
|
2608
|
+
{{ option.title }}
|
|
2609
|
+
</option>
|
|
2610
|
+
</select>
|
|
2611
|
+
</label>
|
|
2612
|
+
<span v-else class="min-w-0 truncate text-xs font-semibold text-amber-900" :title="manualReplacementCapabilityDraftLabel(effectiveBlock)">
|
|
2613
|
+
{{ manualReplacementCapabilityDraftLabel(effectiveBlock) }}
|
|
2614
|
+
</span>
|
|
2615
|
+
<button
|
|
2616
|
+
type="button"
|
|
2617
|
+
class="workbench-card-action inline-flex h-6 max-w-[108px] min-w-0 shrink-0 items-center justify-center rounded-md border border-amber-300 bg-white px-2 text-xs font-semibold text-amber-800 transition hover:border-amber-400 hover:bg-amber-100"
|
|
2618
|
+
:aria-label="manualReplacementActionLabel(effectiveBlock)"
|
|
2619
|
+
:title="manualReplacementActionLabel(effectiveBlock)"
|
|
2620
|
+
@click="replaceManualPlaceholder(effectiveBlock)"
|
|
2621
|
+
>
|
|
2622
|
+
<span class="min-w-0 truncate">{{ manualReplacementPrimaryActionLabel(effectiveBlock) }}</span>
|
|
2623
|
+
</button>
|
|
2624
|
+
</div>
|
|
2625
|
+
</div>
|
|
2626
|
+
</template>
|
|
2627
|
+
|
|
2628
|
+
<div v-else class="rounded-lg border border-slate-100 bg-slate-50 px-4 py-5 text-sm leading-6 text-slate-500">
|
|
2629
|
+
{{ effectiveBlock.title || '未命名卡片' }}
|
|
2630
|
+
</div>
|
|
2631
|
+
</template>
|
|
2632
|
+
|
|
2633
|
+
<template v-else-if="effectiveBlock.blockType === 'form' && isFormBlockData(effectiveBlock.form)">
|
|
2634
|
+
<div class="space-y-4 overflow-y-auto">
|
|
2635
|
+
<div class="flex items-center justify-between rounded-lg bg-slate-50 px-4 py-3 text-xs text-slate-500">
|
|
2636
|
+
<span>草稿状态:{{ effectiveBlock.form.status === 'submitted' ? '已提交' : '编辑中' }}</span>
|
|
2637
|
+
<span>已完成 {{ formCompletedCount(effectiveBlock.id, effectiveBlock.form) }}/{{ effectiveBlock.form.fields.length }}</span>
|
|
2638
|
+
</div>
|
|
2639
|
+
<div class="space-y-4">
|
|
2640
|
+
<label v-for="field in compactLimit(effectiveBlock.form.fields, 2, 3)" :key="field.id" class="block space-y-2">
|
|
2641
|
+
<span class="text-sm font-medium text-slate-800">{{ field.label }}<span v-if="field.required" class="ml-1 text-rose-500">*</span></span>
|
|
2642
|
+
<textarea v-if="field.type === 'textarea'" v-model="formValues(effectiveBlock.id)[field.id] as string" class="min-h-[92px] w-full rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm" :placeholder="field.placeholder" />
|
|
2643
|
+
<select v-else-if="field.type === 'select' || field.type === 'user'" v-model="formValues(effectiveBlock.id)[field.id] as string" class="h-11 w-full rounded-lg border border-slate-200 bg-white px-3 text-sm text-slate-700">
|
|
2644
|
+
<option value="">{{ field.type === 'user' ? '请选择人员' : '请选择' }}</option>
|
|
2645
|
+
<option v-for="option in field.options || []" :key="option" :value="option">{{ option }}</option>
|
|
2646
|
+
</select>
|
|
2647
|
+
<input v-else v-model="formValues(effectiveBlock.id)[field.id] as string" :type="renderFieldType(field)" class="h-11 w-full rounded-lg border border-slate-200 bg-white px-3 text-sm" :placeholder="field.placeholder" />
|
|
2648
|
+
</label>
|
|
2649
|
+
</div>
|
|
2650
|
+
<div class="flex justify-end">
|
|
2651
|
+
<button type="button" class="inline-flex items-center rounded-full bg-[#1f4fd4] px-5 py-2 text-sm font-medium text-white hover:bg-[#163eab]" @click="emit('submitForm', effectiveBlock.id, formValues(effectiveBlock.id))">
|
|
2652
|
+
<Send class="mr-2 h-4 w-4" />提交表单
|
|
2653
|
+
</button>
|
|
2654
|
+
</div>
|
|
2655
|
+
</div>
|
|
2656
|
+
</template>
|
|
2657
|
+
|
|
2658
|
+
<template v-else-if="effectiveBlock.blockType === 'survey' && isSurveyBlockData(effectiveBlock.survey)">
|
|
2659
|
+
<div class="space-y-5 overflow-y-auto">
|
|
2660
|
+
<div class="flex items-center justify-between rounded-lg bg-slate-50 px-4 py-3 text-xs text-slate-500">
|
|
2661
|
+
<span>进度 {{ effectiveBlock.survey.progress.current }}/{{ effectiveBlock.survey.progress.total }}</span>
|
|
2662
|
+
<span>{{ effectiveBlock.survey.status === 'submitted' ? '已提交' : '待提交' }}</span>
|
|
2663
|
+
</div>
|
|
2664
|
+
<div class="space-y-4">
|
|
2665
|
+
<div v-for="(question, questionIndex) in compactLimit(effectiveBlock.survey.questions, 1, 2)" :key="question.id" class="rounded-lg border border-slate-100 p-4">
|
|
2666
|
+
<div class="mb-3 text-sm font-semibold text-slate-900">{{ questionIndex + 1 }}. {{ question.label }}</div>
|
|
2667
|
+
<textarea v-if="question.type === 'text'" v-model="surveyAnswers(effectiveBlock.id)[question.id] as string" class="min-h-[82px] w-full rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm" placeholder="请输入补充说明" />
|
|
2668
|
+
<div v-else-if="question.type === 'score'" class="flex flex-wrap gap-2">
|
|
2669
|
+
<button v-for="option in Array.from({ length: question.scale || 5 }, (_, index) => String(index + 1))" :key="option" type="button" :class="surveyAnswers(effectiveBlock.id)[question.id] === option ? 'bg-[#1f4fd4] text-white' : 'bg-slate-100 text-slate-600 hover:bg-slate-200'" class="flex h-9 w-9 items-center justify-center rounded-full text-xs font-semibold transition" @click="surveyAnswers(effectiveBlock.id)[question.id] = option">{{ option }}</button>
|
|
2670
|
+
</div>
|
|
2671
|
+
<div v-else-if="question.type === 'matrix'" class="overflow-hidden rounded-lg border border-slate-100">
|
|
2672
|
+
<div v-for="row in question.rows || []" :key="row" class="grid grid-cols-[minmax(90px,1fr)_2fr] border-b border-slate-100 last:border-b-0">
|
|
2673
|
+
<div class="bg-slate-50 px-3 py-3 text-xs font-medium text-slate-600">{{ row }}</div>
|
|
2674
|
+
<div class="flex flex-wrap gap-2 px-3 py-2">
|
|
2675
|
+
<button v-for="option in question.options" :key="`${row}-${option}`" type="button" :class="matrixAnswerValue(effectiveBlock.id, question.id, row) === option ? 'bg-[#1f4fd4] text-white' : 'bg-slate-100 text-slate-600 hover:bg-slate-200'" class="rounded-full px-3 py-1.5 text-xs font-medium transition" @click="updateMatrixAnswer(effectiveBlock.id, question.id, row, option)">{{ option }}</button>
|
|
2676
|
+
</div>
|
|
2677
|
+
</div>
|
|
2678
|
+
</div>
|
|
2679
|
+
<div v-else class="flex flex-wrap gap-2">
|
|
2680
|
+
<button v-for="option in question.options" :key="option" type="button" :class="(question.type === 'multiple' ? multipleAnswerIncludes(effectiveBlock.id, question.id, option) : surveyAnswers(effectiveBlock.id)[question.id] === option) ? 'bg-[#1f4fd4] text-white' : 'bg-slate-100 text-slate-600 hover:bg-slate-200'" class="rounded-full px-3 py-2 text-xs font-medium transition" @click="surveyAnswers(effectiveBlock.id)[question.id] = question.type === 'multiple' ? toggleMultiValue(surveyAnswers(effectiveBlock.id)[question.id], option) : option">{{ option }}</button>
|
|
2681
|
+
</div>
|
|
2682
|
+
</div>
|
|
2683
|
+
</div>
|
|
2684
|
+
<div class="flex justify-end"><button type="button" class="inline-flex items-center rounded-full bg-[#1f4fd4] px-5 py-2 text-sm font-medium text-white hover:bg-[#163eab]" @click="emit('submitSurvey', effectiveBlock.id, surveyAnswers(effectiveBlock.id))"><ClipboardCheck class="mr-2 h-4 w-4" />提交问卷</button></div>
|
|
2685
|
+
</div>
|
|
2686
|
+
</template>
|
|
2687
|
+
|
|
2688
|
+
<template v-else-if="effectiveBlock.blockType === 'action' && isActionGroupData(effectiveBlock.actionGroup)">
|
|
2689
|
+
<div class="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
|
|
2690
|
+
<button v-for="item in compactLimit(effectiveBlock.actionGroup.buttons, 2, 4)" :key="item.id" type="button" class="group rounded-lg border border-slate-100 bg-white p-4 text-left transition hover:border-[#bfd1ff] hover:bg-[#f5f9ff]" @click="emit('executeAction', effectiveBlock.id, item.id, item.label)">
|
|
2691
|
+
<div class="flex items-center justify-between"><div class="flex h-10 w-10 items-center justify-center rounded-lg bg-[#edf3ff] text-[#1f4fd4]"><Play class="h-4 w-4" /></div><ArrowRight class="h-4 w-4 text-slate-300 transition group-hover:translate-x-1 group-hover:text-[#1f4fd4]" /></div>
|
|
2692
|
+
<div class="mt-4 text-sm font-semibold text-slate-900">{{ item.label }}</div>
|
|
2693
|
+
<p class="mt-2 text-xs leading-5 text-slate-500">{{ item.description }}</p>
|
|
2694
|
+
</button>
|
|
2695
|
+
</div>
|
|
2696
|
+
</template>
|
|
2697
|
+
|
|
2698
|
+
<template v-else-if="effectiveBlock.blockType === 'workflow' && isWorkflowBlockData(effectiveBlock.workflow)">
|
|
2699
|
+
<div class="space-y-5 overflow-y-auto">
|
|
2700
|
+
<div v-if="effectiveBlock.workflow.statusBoard" class="grid gap-3 sm:grid-cols-3">
|
|
2701
|
+
<div v-for="item in effectiveBlock.workflow.statusBoard" :key="item.label" class="rounded-lg bg-slate-50 px-4 py-3"><div class="text-xs text-slate-500">{{ item.label }}</div><div class="mt-1 text-xl font-semibold text-slate-900">{{ item.count }}</div></div>
|
|
2702
|
+
</div>
|
|
2703
|
+
<div class="space-y-4">
|
|
2704
|
+
<div v-for="(step, index) in compactLimit(effectiveBlock.workflow.steps, 2, 4)" :key="`${step.time}-${step.label}`" class="flex gap-4">
|
|
2705
|
+
<div class="flex flex-col items-center"><div :class="step.status === 'done' ? 'bg-emerald-100 text-emerald-600' : step.status === 'running' ? 'bg-[#edf3ff] text-[#1f4fd4]' : 'bg-slate-100 text-slate-500'" class="flex h-9 w-9 items-center justify-center rounded-full"><CircleCheck class="h-4 w-4" /></div><div v-if="index < effectiveBlock.workflow.steps.length - 1" class="mt-2 h-full w-px bg-slate-200" /></div>
|
|
2706
|
+
<div class="flex-1 pb-6"><div class="flex items-center justify-between gap-3"><div class="text-sm font-semibold text-slate-900">{{ step.label }}</div><span class="rounded-full bg-slate-100 px-2.5 py-1 text-[11px] text-slate-600">{{ step.time }}</span></div><div class="mt-1 text-xs text-slate-500">责任主体:{{ step.owner || '系统' }}</div><div v-if="step.description" class="mt-2 text-xs leading-5 text-slate-400">{{ step.description }}</div></div>
|
|
2707
|
+
</div>
|
|
2708
|
+
</div>
|
|
2709
|
+
</div>
|
|
2710
|
+
</template>
|
|
2711
|
+
|
|
2712
|
+
<template v-else-if="effectiveBlock.blockType === 'report' && isReportBlockData(effectiveBlock.report)">
|
|
2713
|
+
<div class="space-y-5 overflow-y-auto">
|
|
2714
|
+
<div class="flex flex-col gap-4 rounded-lg bg-gradient-to-br from-[#0f172a] to-[#1e3a8a] p-6 text-white lg:flex-row lg:items-end lg:justify-between">
|
|
2715
|
+
<div><div class="text-xs uppercase text-blue-100">Report Artifact</div><div class="mt-2 text-2xl font-semibold">第 {{ effectiveBlock.report.version }} 版管理简报</div><p class="mt-3 max-w-2xl text-sm leading-6 text-blue-50">{{ effectiveBlock.report.summary }}</p></div>
|
|
2716
|
+
<button type="button" class="inline-flex items-center rounded-full bg-white/12 px-5 py-2 text-sm font-medium text-white hover:bg-white/20" @click="emit('generateReport', effectiveBlock.id)"><FileBarChart2 class="mr-2 h-4 w-4" />生成新版本</button>
|
|
2717
|
+
</div>
|
|
2718
|
+
<div class="grid gap-4 lg:grid-cols-3">
|
|
2719
|
+
<div v-for="section in compactLimit(effectiveBlock.report.sections, 1, 2)" :key="section.title" class="rounded-lg border border-slate-100 bg-white p-5"><div class="text-sm font-semibold text-slate-900">{{ section.title }}</div><p class="mt-3 text-sm leading-6 text-slate-600">{{ section.body }}</p></div>
|
|
2720
|
+
</div>
|
|
2721
|
+
</div>
|
|
2722
|
+
</template>
|
|
2723
|
+
|
|
2724
|
+
<div v-else class="rounded-lg border border-slate-100 bg-slate-50 px-4 py-5 text-sm leading-6 text-slate-500">
|
|
2725
|
+
{{ effectiveBlock.title || '暂未匹配渲染器' }}
|
|
2726
|
+
</div>
|
|
2727
|
+
</div>
|
|
2728
|
+
</template>
|