@fses/workbench-app 0.2.15 → 0.2.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/WORKBENCH-CLOSURE.json +18 -12
  2. package/dist/Workspace-r8ayksVF.js +23176 -0
  3. package/dist/canvas/api/index.js +1 -1
  4. package/dist/{canvasFacade-B2EHgdqA.js → canvasFacade-B8jYm_aO.js} +748 -748
  5. package/dist/cardFactory-DmEBcCf4.js +1460 -0
  6. package/dist/extensions/index.js +1 -1
  7. package/dist/fses-workbench-app.js +5 -5
  8. package/dist/{index-C0L5xASu.js → index-DEOR_GPc.js} +350 -346
  9. package/dist/internal/personal-workbench/fde-skill-cards/runtime/fdeSkillProtocolChartDisplayData.d.ts +0 -5
  10. package/dist/internal/personal-workbench/lib/assistantPersonaProfiles.d.ts +6 -6
  11. package/dist/internal/personal-workbench/lib/cardStyleConfig.d.ts +26 -26
  12. package/dist/internal/personal-workbench/lib/echartsOptionEditorBridge.d.ts +0 -5
  13. package/dist/internal/personal-workbench/lib/historyCardBindingRestore.fixture.d.ts +0 -5
  14. package/dist/internal/personal-workbench/lib/runtimePrimitiveRegistry.d.ts +1 -1
  15. package/dist/internal/personal-workbench/lib/vueRuntimeAdapters.d.ts +0 -5
  16. package/dist/internal/personal-workbench/lib/workbenchCanvasBusinessGapChecklist.d.ts +1 -1
  17. package/dist/internal/personal-workbench/lib/workbenchCardRecommendationFallback.d.ts +1 -1
  18. package/dist/internal/personal-workbench/lib/workbenchCardRecommendationReturnItemUpsert.d.ts +0 -5
  19. package/dist/internal/personal-workbench/lib/workbenchDataBindingBadge.d.ts +0 -5
  20. package/dist/internal/personal-workbench/lib/workbenchImageComposeEntry.d.ts +1 -1
  21. package/dist/internal/personal-workbench/lib/workbenchLayout.d.ts +0 -5
  22. package/dist/runtime/index.js +1 -1
  23. package/dist/style.css +1 -1
  24. package/dist/{useWorkbenchRuntime-DLf_FgC7.js → useWorkbenchRuntime-DDD22mdF.js} +7817 -7813
  25. package/dist/version.d.ts +1 -1
  26. package/dist/{workbenchCustomComponentRegistry-Bt94Lgko.js → workbenchCustomComponentRegistry-CWUPjCnJ.js} +74 -74
  27. package/node_modules/@byteluck-fe/locale-message/README.md +2 -0
  28. package/node_modules/@byteluck-fe/locale-message/dist/index.d.ts +37 -0
  29. package/node_modules/@byteluck-fe/locale-message/dist/locale-message.js +55 -0
  30. package/node_modules/@byteluck-fe/locale-message/package.json +37 -0
  31. package/node_modules/@fses/ai-chat/dist/components/ContextUsageRing.vue.d.ts +5 -0
  32. package/node_modules/@fses/ai-chat/dist/components/FsesAiChat.vue.d.ts +5 -0
  33. package/node_modules/@fses/ai-chat/dist/fses-ai-chat.js +6225 -6075
  34. package/node_modules/@fses/ai-chat/dist/fses-ai-chat.umd.cjs +17 -19
  35. package/node_modules/@fses/ai-chat/dist/style.css +1 -1
  36. package/node_modules/@fses/ai-chat/dist/utils/attachment-upload.d.ts +0 -5
  37. package/node_modules/@fses/ai-chat/package.json +4 -3
  38. package/node_modules/@fses/workbench-card/dist/fses-workbench-card-renderers.js +10144 -9914
  39. package/node_modules/@fses/workbench-card/dist/fses-workbench-card.js +1517 -1503
  40. package/node_modules/@fses/workbench-card/dist/fses-workbench-card.umd.cjs +1 -1
  41. package/node_modules/@fses/workbench-card/dist/renderers/chart/chartRendererRegistry.d.ts +97 -97
  42. package/node_modules/@fses/workbench-card/dist/renderers/style.css +1 -1
  43. package/node_modules/@fses/workbench-card/package.json +4 -1
  44. package/node_modules/@fses/workbench-card/src/registry/cardRegistry.ts +99 -98
  45. package/node_modules/@fses/workbench-card/src/registry/compositeCardPatterns.ts +31 -30
  46. package/node_modules/@fses/workbench-card/src/registry/echartsTemplateCategories.ts +24 -23
  47. package/node_modules/@fses/workbench-card/src/registry/echartsTemplateRegistry.generated.js +765 -764
  48. package/node_modules/@fses/workbench-card/src/registry/echartsTemplateRegistry.generated.ts +765 -764
  49. package/node_modules/@fses/workbench-card/src/renderers/WorkbenchBlockRenderer.vue +143 -129
  50. package/node_modules/@fses/workbench-card/src/renderers/chart/ChartRegistry.vue +4 -3
  51. package/node_modules/@fses/workbench-card/src/renderers/chart/EChartsProtocolRenderer.vue +2 -1
  52. package/node_modules/@fses/workbench-card/src/renderers/chart/chartRendererRegistry.ts +99 -98
  53. package/node_modules/@fses/workbench-card/src/renderers/chart/useEchart.ts +30 -29
  54. package/node_modules/@fses/workbench-card/src/renderers/native/nativeBindings.ts +11 -10
  55. package/node_modules/@fses/workbench-card/src/renderers/nested/nestedBlockBindings.ts +102 -101
  56. package/node_modules/@fses/workbench-card/src/renderers/reference-composite/referenceCompositeBindings.ts +364 -363
  57. package/node_modules/@fses/workbench-card/src/renderers/reference-composite/referenceRiskAndStrategyBindings.ts +90 -89
  58. package/node_modules/@fses/workbench-card/src/renderers/useWorkbenchBlockRendererBindings.ts +33 -32
  59. package/package.json +4 -3
  60. package/dist/Workspace-_r17G1XR.js +0 -22895
  61. package/dist/cardFactory-BK3CA-Gn.js +0 -1443
@@ -4,6 +4,7 @@
4
4
  * @created 2026-05-10
5
5
  */
6
6
  <script setup lang="ts">
7
+ import { getLocaleText } from '@byteluck-fe/locale-message'
7
8
  import { Table as ATable } from 'ant-design-vue';
8
9
  import {
9
10
  ArrowRight,
@@ -393,7 +394,7 @@ const {
393
394
  class="h-full min-h-0"
394
395
  />
395
396
  <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="text-xs text-blue-500" data-i18n="FWC.46911787579406685" >{{ getLocaleText('FWC.46911787579406685') }}</div>
397
398
  <div class="mt-1 text-lg font-semibold">{{ effectiveBlock.title }}</div>
398
399
  </div>
399
400
  </template>
@@ -402,7 +403,7 @@ const {
402
403
  <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
404
  <div class="min-w-0">
404
405
  <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
+ {{ dataBindingNeedsHumanIntervention(effectiveBlock) ? getLocaleText('FWC.cc9b1787580395753') : getLocaleText('FWC.c6631787581328122') }}
406
407
  </div>
407
408
  <div class="mt-1 truncate text-xs font-semibold leading-4 text-slate-950" :title="effectiveBlock.title || dataBindingFailureRegistryLabel(effectiveBlock)">
408
409
  {{ effectiveBlock.title || dataBindingFailureRegistryLabel(effectiveBlock) }}
@@ -429,7 +430,7 @@ const {
429
430
  </div>
430
431
  <div v-else-if="effectiveBlock.meta?.organizationKind === 'ai_shortcut'" class="grid gap-2">
431
432
  <button
432
- v-for="shortcut in ['只看图表卡能力', '把全部验收卡按分类说明一下', '生成 CEO 角色首页推荐布局', '检查当前画布哪些卡片适合改成大屏']"
433
+ v-for="shortcut in [getLocaleText('FWC.ddf21787580396297'), getLocaleText('FWC.d0a81787579406722'), getLocaleText('FWC.5c5e1787579281874'), getLocaleText('FWC.992a1787579239342')]"
433
434
  :key="shortcut"
434
435
  type="button"
435
436
  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"
@@ -462,11 +463,11 @@ const {
462
463
  <div v-else-if="effectiveBlock.meta?.organizationKind === 'section_description'" class="rounded-lg border border-slate-200 bg-slate-50 px-3 py-2">
463
464
  <div class="flex flex-wrap items-center gap-2">
464
465
  <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
+ {{ textValue(activeTabFor(effectiveBlock).shortName, getLocaleText('FWC.a48d1787581610611')) }} · {{ numberValue(activeTabFor(effectiveBlock).count) }} 个能力
466
467
  </span>
467
- <span class="text-[11px] text-slate-500">{{ textValue(activeTabFor(effectiveBlock).id, 'all-capabilities') === 'all-capabilities' ? '当前可配置完整画布。' : '当前分类排版会同步到全部视图。' }}</span>
468
+ <span class="text-[11px] text-slate-500">{{ textValue(activeTabFor(effectiveBlock).id, 'all-capabilities') === 'all-capabilities' ? getLocaleText('FWC.ce691787579718538') : getLocaleText('FWC.07b61787579281906') }}</span>
468
469
  </div>
469
- <p class="mt-1 text-xs leading-5 text-slate-600">{{ textValue(activeTabFor(effectiveBlock).description, '展示当前能力分类的业务场景和使用边界。') }}</p>
470
+ <p class="mt-1 text-xs leading-5 text-slate-600">{{ textValue(activeTabFor(effectiveBlock).description, getLocaleText('FWC.77be1787579151816')) }}</p>
470
471
  </div>
471
472
  </template>
472
473
 
@@ -649,9 +650,9 @@ const {
649
650
  />
650
651
  </svg>
651
652
  <div class="hidden">
652
- <span class="truncate">基准线</span>
653
- <span class="truncate text-center">异动区间</span>
654
- <span class="truncate text-right">待回填</span>
653
+ <span class="truncate" data-i18n="FWC.043d1787581554086" >{{ getLocaleText('FWC.043d1787581554086') }}</span>
654
+ <span class="truncate text-center" data-i18n="FWC.c7671787581328486" >{{ getLocaleText('FWC.c7671787581328486') }}</span>
655
+ <span class="truncate text-right" data-i18n="FWC.09361787581554284" >{{ getLocaleText('FWC.09361787581554284') }}</span>
655
656
  </div>
656
657
  </div>
657
658
  </div>
@@ -898,7 +899,7 @@ const {
898
899
  >
899
900
  <div class="flex h-9 shrink-0 items-center justify-between gap-2 border-b border-slate-100 bg-slate-50 px-3">
900
901
  <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
+ <span class="shrink-0 text-[11px] font-semibold text-slate-400" data-i18n="FWC.a79e1787579718598" >{{ getLocaleText('FWC.a79e1787579718598', {p0: ((effectiveData as TableRowsData).rows || []).length}) }}</span>
902
903
  </div>
903
904
 
904
905
  <div
@@ -964,7 +965,7 @@ const {
964
965
 
965
966
  <template v-else-if="effectiveData?.shape === 'insightNarrative'">
966
967
  <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="flex items-center gap-2 text-sm font-semibold text-slate-900"><Sparkles class="h-4 w-4 text-[#1f4fd4]" /><span data-i18n="FWC.b4211787580396404" >{{ getLocaleText('FWC.b4211787580396404') }}</span></div>
968
969
  <div class="space-y-3">
969
970
  <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
971
  <div class="h-2.5 w-2.5 shrink-0 rounded-full bg-[#1f4fd4]" />
@@ -973,7 +974,7 @@ const {
973
974
  </div>
974
975
  <div v-if="density !== 'thumbnail'" class="flex items-center justify-between text-xs text-slate-500">
975
976
  <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
+ <span v-if="typeof (effectiveData as InsightNarrativeData).confidence === 'number'" data-i18n="FWC.b9da1787579406769" >{{ getLocaleText('FWC.b9da1787579406769', {p0: (((effectiveData as InsightNarrativeData).confidence || 0) * 100).toFixed(0)}) }}</span>
977
978
  </div>
978
979
  </div>
979
980
  </template>
@@ -981,7 +982,7 @@ const {
981
982
  <template v-else-if="effectiveData?.shape === 'taskSummary'">
982
983
  <div class="h-full min-h-0 w-full space-y-4 overflow-y-auto">
983
984
  <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 v-for="item in [[getLocaleText('FWC.a48d1787581610611'), (effectiveData as TaskSummaryData).total], [getLocaleText('FWC.b0111787581611077'), (effectiveData as TaskSummaryData).dueToday], [getLocaleText('FWC.02241787581611375'), (effectiveData as TaskSummaryData).overdue], [getLocaleText('FWC.5a8b1787581611928'), (effectiveData as TaskSummaryData).completed]]" :key="String(item[0])" class="rounded-lg border border-slate-100 bg-slate-50/80 px-3 py-2">
985
986
  <div class="text-[11px] text-slate-500">{{ item[0] }}</div>
986
987
  <div class="mt-1 text-lg font-semibold text-slate-900">{{ item[1] }}</div>
987
988
  </div>
@@ -1020,10 +1021,18 @@ const {
1020
1021
  </div>
1021
1022
  </div>
1022
1023
  <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>
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"><ThermometerSun class="h-3.5 w-3.5" />
1025
+ <span data-i18n="FWC.b4ef1787581612182" >{{ getLocaleText('FWC.b4ef1787581612182') }}</span>
1026
+ </div><div class="mt-1 text-sm font-semibold text-slate-900">{{ formatWeatherTemp((effectiveData as WeatherCurrentData).feelsLikeC) }}</div></div>
1027
+ <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" />
1028
+ <span data-i18n="FWC.cf351787581612422" >{{ getLocaleText('FWC.cf351787581612422') }}</span>
1029
+ </div><div class="mt-1 text-sm font-semibold text-slate-900">{{ typeof (effectiveData as WeatherCurrentData).humidityPct === 'number' ? `${(effectiveData as WeatherCurrentData).humidityPct}%` : '--' }}</div></div>
1030
+ <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" />
1031
+ <span data-i18n="FWC.23801787581612666" >{{ getLocaleText('FWC.23801787581612666') }}</span>
1032
+ </div><div class="mt-1 text-sm font-semibold text-slate-900">{{ typeof (effectiveData as WeatherCurrentData).precipitationPct === 'number' ? `${(effectiveData as WeatherCurrentData).precipitationPct}%` : '--' }}</div></div>
1033
+ <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" />
1034
+ <span data-i18n="FWC.eae81787581612905" >{{ getLocaleText('FWC.eae81787581612905') }}</span>
1035
+ </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
1036
  </div>
1028
1037
  <div class="grid gap-2" :style="{ gridTemplateColumns: `repeat(${Math.max(1, compactLimit((effectiveData as WeatherCurrentData).forecast, 2, 2).length)}, minmax(0, 1fr))` }">
1029
1038
  <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">
@@ -1080,7 +1089,7 @@ const {
1080
1089
 
1081
1090
  <template v-else-if="effectiveData?.shape === 'embeddedFrame'">
1082
1091
  <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 || '缺少可嵌入页面地址。' }}
1092
+ {{ (effectiveData as EmbeddedFrameData).fallbackText || getLocaleText('FWC.d2da1787579718726') }}
1084
1093
  </div>
1085
1094
  <div v-else class="flex h-full min-h-0 w-full flex-col overflow-hidden border border-slate-100 bg-white">
1086
1095
  <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" />
@@ -1236,12 +1245,12 @@ const {
1236
1245
  >
1237
1246
  <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
1247
  <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>
1248
+ <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, getLocaleText('FWC.64611787581328642')) }}</div>
1240
1249
  </div>
1241
1250
  <div class="min-w-0">
1242
1251
  <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>
1252
+ <h4 class="mt-0.5 truncate text-sm font-semibold leading-5 text-white" data-i18n-title="FWC.ec5d1787579718796" :title="getLocaleText('FWC.ec5d1787579718796')">{{ getLocaleText('FWC.ec5d1787579718796') }}</h4>
1253
+ <p class="workbench-reference-risk-narrative max-h-9 overflow-hidden text-xs leading-[18px] text-slate-200" data-i18n-title="FWC.682b1787578636647" :title="getLocaleText('FWC.682b1787578636647')">{{ getLocaleText('FWC.682b1787578636647') }}</p>
1245
1254
  </div>
1246
1255
  </section>
1247
1256
  <section
@@ -1264,7 +1273,7 @@ const {
1264
1273
  </div>
1265
1274
  <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
1275
  <span class="text-sm leading-none">⌄</span>
1267
- <span class="truncate text-right leading-4">一键风险全景下钻</span>
1276
+ <span class="truncate text-right leading-4" data-i18n="FWC.61ae1787580014686" >{{ getLocaleText('FWC.61ae1787580014686') }}</span>
1268
1277
  </div>
1269
1278
  </section>
1270
1279
  </div>
@@ -1353,7 +1362,7 @@ const {
1353
1362
  <div class="grid grid-cols-[minmax(0,1fr)_auto] items-center gap-2 text-sm leading-5">
1354
1363
  <span class="truncate text-slate-500" :title="nestedBlockItemLabel(item, index + 1)">{{ nestedBlockItemLabel(item, index + 1) }}</span>
1355
1364
  <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>
1365
+ <span v-else :class="nestedBlockPillClasses(item)" :title="nestedBlockItemValue(item)">{{ nestedBlockToneClass(item) === 'critical' ? getLocaleText('FWC.51971787581613139') : nestedBlockToneClass(item) === 'warning' ? getLocaleText('FWC.7c7e1787581554823') : getLocaleText('FWC.86581787581613380') }}</span>
1357
1366
  </div>
1358
1367
  <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
1368
  <div class="grid grid-cols-[minmax(0,1fr)_auto] items-center gap-2 text-xs leading-5 text-slate-500">
@@ -1388,7 +1397,7 @@ const {
1388
1397
  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
1398
  >
1390
1399
  <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>
1400
+ <h4 class="truncate text-sm font-semibold leading-5 text-slate-900" data-i18n="FWC.0fbc1787581068510" >{{ getLocaleText('FWC.0fbc1787581068510') }}</h4>
1392
1401
  <div class="mt-2 grid min-h-0 gap-1.5 overflow-hidden" style="grid-auto-rows: minmax(0, 1fr);">
1393
1402
  <div
1394
1403
  v-for="(item, index) in referenceOperationHealthProgressItems(effectiveData as CustomCanvasData)"
@@ -1405,7 +1414,7 @@ const {
1405
1414
  </div>
1406
1415
  </section>
1407
1416
  <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>
1417
+ <h4 class="truncate text-sm font-semibold leading-5 text-slate-900" data-i18n="FWC.6e701787580015004" >{{ getLocaleText('FWC.6e701787580015004') }}</h4>
1409
1418
  <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
1419
  <div
1411
1420
  v-for="(item, index) in referenceOperationHealthTrendItems(effectiveData as CustomCanvasData)"
@@ -1419,9 +1428,9 @@ const {
1419
1428
  </div>
1420
1429
  </section>
1421
1430
  <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>
1431
+ <h4 class="truncate text-sm font-semibold leading-5 text-slate-900" data-i18n="FWC.59d11787581328789" >{{ getLocaleText('FWC.59d11787581328789') }}</h4>
1423
1432
  <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>
1433
+ <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))" data-i18n="FWC.b9b91787581613640" >{{ getLocaleText('FWC.b9b91787581613640') }}</div>
1425
1434
  <div class="grid min-w-0 gap-1 overflow-hidden text-xs leading-4">
1426
1435
  <div
1427
1436
  v-for="(item, index) in referenceOperationHealthStructureItems(effectiveData as CustomCanvasData)"
@@ -1483,7 +1492,7 @@ const {
1483
1492
  <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
1493
  {{ nestedBlockItemValue(item) || '--' }}
1485
1494
  </strong>
1486
- <p class="min-w-0 truncate text-slate-500" :title="nestedBlockItemDetail(item)">{{ nestedBlockItemDetail(item) || '等待补充业务口径后问数' }}</p>
1495
+ <p class="min-w-0 truncate text-slate-500" :title="nestedBlockItemDetail(item)">{{ nestedBlockItemDetail(item) || getLocaleText('FWC.e3cb1787579586988') }}</p>
1487
1496
  </template>
1488
1497
  <template v-else>
1489
1498
  <span class="min-w-0 truncate font-semibold text-slate-700">{{ nestedBlockItemLabel(item, index) }}</span>
@@ -1503,7 +1512,7 @@ const {
1503
1512
  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
1513
  >
1505
1514
  <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>
1515
+ <h4 class="truncate text-sm font-semibold leading-5 text-slate-900" data-i18n="FWC.3f511787580558074" >{{ getLocaleText('FWC.3f511787580558074') }}</h4>
1507
1516
  <div
1508
1517
  v-for="(item, index) in referenceHrOrganizationMetrics(effectiveData as CustomCanvasData)"
1509
1518
  :key="`hr-org-metric-${index}`"
@@ -1515,7 +1524,7 @@ const {
1515
1524
  </div>
1516
1525
  </section>
1517
1526
  <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>
1527
+ <h4 class="truncate text-sm font-semibold leading-5 text-slate-900" data-i18n="FWC.b5861787580558189" >{{ getLocaleText('FWC.b5861787580558189') }}</h4>
1519
1528
  <div class="mt-2 grid min-h-0 content-start gap-1.5 overflow-hidden">
1520
1529
  <div
1521
1530
  v-for="(item, index) in referenceHrOrganizationRows(effectiveData as CustomCanvasData)"
@@ -1530,7 +1539,7 @@ const {
1530
1539
  </div>
1531
1540
  </section>
1532
1541
  <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>
1542
+ <h4 class="truncate text-sm font-semibold leading-5 text-slate-900" data-i18n="FWC.b2331787580558321" >{{ getLocaleText('FWC.b2331787580558321') }}</h4>
1534
1543
  <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
1544
  <div
1536
1545
  v-for="(item, index) in referenceHrCostTrendItems(effectiveData as CustomCanvasData).slice(0, 6)"
@@ -1556,10 +1565,10 @@ const {
1556
1565
  >
1557
1566
  <span class="truncate font-semibold text-slate-700">{{ nestedBlockItemLabel(item, index) }}</span>
1558
1567
  <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>
1568
+ <span class="truncate text-slate-600">{{ nestedBlockItemDetail(item) || getLocaleText('FWC.3b8f1787579902112') }}</span>
1560
1569
  </section>
1561
1570
  <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>
1571
+ <h4 class="truncate text-sm font-semibold leading-5 text-slate-900" data-i18n="FWC.3aad1787580558437" >{{ getLocaleText('FWC.3aad1787580558437') }}</h4>
1563
1572
  <div class="mt-2 grid min-h-0 content-start gap-1.5 overflow-hidden">
1564
1573
  <div
1565
1574
  v-for="(item, index) in referenceHrRiskRows(effectiveData as CustomCanvasData)"
@@ -1569,7 +1578,7 @@ const {
1569
1578
  >
1570
1579
  <i :class="nestedBlockDotClasses(item)" />
1571
1580
  <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>
1581
+ <span :class="nestedBlockPillClasses(item)" :title="nestedBlockItemValue(item) || nestedBlockItemDetail(item)">{{ nestedBlockItemValue(item) || nestedBlockItemDetail(item) || getLocaleText('FWC.9cb91787581555007') }}</span>
1573
1582
  </div>
1574
1583
  </div>
1575
1584
  </section>
@@ -1579,7 +1588,7 @@ const {
1579
1588
  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
1589
  >
1581
1590
  <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>
1591
+ <h4 class="truncate text-sm font-semibold leading-5 text-slate-900" data-i18n="FWC.fa111787580558556" >{{ getLocaleText('FWC.fa111787580558556') }}</h4>
1583
1592
  <div class="mt-2 grid min-h-0 content-start gap-1.5 overflow-hidden">
1584
1593
  <div
1585
1594
  v-for="(item, index) in referenceHrPeopleCostItems(effectiveData as CustomCanvasData)"
@@ -1593,7 +1602,7 @@ const {
1593
1602
  </div>
1594
1603
  </section>
1595
1604
  <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>
1605
+ <h4 class="truncate text-sm font-semibold leading-5 text-slate-900" data-i18n="FWC.f3191787580396506" >{{ getLocaleText('FWC.f3191787580396506') }}</h4>
1597
1606
  <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
1607
  <div
1599
1608
  v-for="(item, index) in referenceHrCostTrendItems(effectiveData as CustomCanvasData)"
@@ -1613,7 +1622,7 @@ const {
1613
1622
  :title="nestedBlockItemTitle(item, index + 2)"
1614
1623
  >
1615
1624
  <span class="truncate font-semibold text-slate-600">{{ nestedBlockItemLabel(item, index + 2) }}</span>
1616
- <span :class="nestedBlockPillClasses(item)" :title="nestedBlockItemValue(item)">{{ nestedBlockItemValue(item) || '待确认' }}</span>
1625
+ <span :class="nestedBlockPillClasses(item)" :title="nestedBlockItemValue(item)">{{ nestedBlockItemValue(item) || getLocaleText('FWC.9cb91787581555007') }}</span>
1617
1626
  </div>
1618
1627
  </div>
1619
1628
  </section>
@@ -1623,7 +1632,7 @@ const {
1623
1632
  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
1633
  >
1625
1634
  <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>
1635
+ <h4 class="truncate text-sm font-semibold leading-5 text-slate-900" data-i18n="FWC.76041787581328976" >{{ getLocaleText('FWC.76041787581328976') }}</h4>
1627
1636
  <div
1628
1637
  v-for="(item, index) in referenceHrTalentMetrics(effectiveData as CustomCanvasData)"
1629
1638
  :key="`hr-talent-metric-${index}`"
@@ -1635,7 +1644,7 @@ const {
1635
1644
  </div>
1636
1645
  </section>
1637
1646
  <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>
1647
+ <h4 class="truncate text-sm font-semibold leading-5 text-slate-900" data-i18n="FWC.1dc71787580558674" >{{ getLocaleText('FWC.1dc71787580558674') }}</h4>
1639
1648
  <div class="mt-2 grid min-h-0 content-start gap-1.5 overflow-hidden">
1640
1649
  <div
1641
1650
  v-for="(item, index) in referenceHrTalentTodoRows(effectiveData as CustomCanvasData)"
@@ -1645,7 +1654,7 @@ const {
1645
1654
  >
1646
1655
  <i :class="nestedBlockDotClasses(item)" />
1647
1656
  <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>
1657
+ <span :class="nestedBlockPillClasses(item)" :title="nestedBlockItemValue(item) || nestedBlockItemDetail(item)">{{ nestedBlockItemValue(item) || nestedBlockItemDetail(item) || getLocaleText('FWC.9cb91787581555007') }}</span>
1649
1658
  </div>
1650
1659
  </div>
1651
1660
  </section>
@@ -1670,15 +1679,15 @@ const {
1670
1679
  </p>
1671
1680
  </div>
1672
1681
  <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>
1682
+ <span class="rounded-full border border-white/20 bg-white/10 px-2.5 py-0.5" data-i18n="FWC.49701787581068641" >{{ getLocaleText('FWC.49701787581068641') }}</span>
1683
+ <span class="rounded-full border border-white/20 bg-white/10 px-2.5 py-0.5" data-i18n="FWC.8fcb1787579587039" >{{ getLocaleText('FWC.8fcb1787579587039', {p0: referenceBidHero(effectiveBlock, effectiveData as CustomCanvasData).route}) }}</span>
1684
+ <span class="rounded-full border border-white/20 bg-white/10 px-2.5 py-0.5" data-i18n="FWC.d5d21787579587092" >{{ getLocaleText('FWC.d5d21787579587092', {p0: referenceBidHero(effectiveBlock, effectiveData as CustomCanvasData).scope}) }}</span>
1685
+ <span class="rounded-full border border-white/20 bg-white/10 px-2.5 py-0.5" data-i18n="FWC.e5701787579587148" >{{ getLocaleText('FWC.e5701787579587148', {p0: referenceBidHero(effectiveBlock, effectiveData as CustomCanvasData).refresh}) }}</span>
1677
1686
  </div>
1678
1687
  </section>
1679
1688
 
1680
1689
  <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>
1690
+ <span class="shrink-0 font-semibold text-slate-500" data-i18n="FWC.59e91787581329149" >{{ getLocaleText('FWC.59e91787581329149') }}</span>
1682
1691
  <div class="flex min-w-0 flex-wrap gap-2 overflow-hidden">
1683
1692
  <span
1684
1693
  v-for="action in referenceBidQuickActions(effectiveData as CustomCanvasData)"
@@ -1706,8 +1715,8 @@ const {
1706
1715
  <section class="grid min-h-[8rem] grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-md border border-slate-200 bg-white">
1707
1716
  <div class="grid h-9 grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-2 border-b border-slate-200 px-3">
1708
1717
  <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>
1718
+ <h4 class="truncate text-sm font-semibold leading-5 text-slate-900" data-i18n="FWC.0ba31787580564177" >{{ getLocaleText('FWC.0ba31787580564177') }}</h4>
1719
+ <span class="truncate text-xs font-semibold text-slate-500" data-i18n="FWC.d6c71787579201521" >{{ getLocaleText('FWC.d6c71787579201521') }}</span>
1711
1720
  </div>
1712
1721
  <div
1713
1722
  class="grid min-h-0 gap-2 overflow-hidden p-2"
@@ -1744,7 +1753,7 @@ const {
1744
1753
  :title="nestedBlockItemTitle(item, index)"
1745
1754
  >
1746
1755
  <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>
1756
+ <span :class="nestedBlockPillClasses(item)" :title="referenceBidSanitizedMetricValue(item, nestedBlockItemDetail(item) || getLocaleText('FWC.9cb91787581555007'))">{{ referenceBidSanitizedMetricValue(item, nestedBlockItemDetail(item) || getLocaleText('FWC.9cb91787581555007')) }}</span>
1748
1757
  </div>
1749
1758
  </div>
1750
1759
  </div>
@@ -1753,14 +1762,14 @@ const {
1753
1762
  <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
1763
  <div class="grid h-9 grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-2 border-b border-slate-200 px-3">
1755
1764
  <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>
1765
+ <h4 class="truncate text-sm font-semibold leading-5 text-slate-900" data-i18n="FWC.c0ad1787579718932" >{{ getLocaleText('FWC.c0ad1787579718932') }}</h4>
1766
+ <span class="truncate text-xs font-semibold text-slate-500" data-i18n="FWC.31f31787579587205" >{{ getLocaleText('FWC.31f31787579587205') }}</span>
1758
1767
  </div>
1759
1768
  <div class="grid min-h-0 overflow-hidden">
1760
1769
  <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>
1770
+ <span class="truncate" data-i18n="FWC.81d31787581068775" >{{ getLocaleText('FWC.81d31787581068775') }}</span>
1771
+ <span class="truncate" data-i18n="FWC.faa31787581329469" >{{ getLocaleText('FWC.faa31787581329469') }}</span>
1772
+ <span class="truncate" data-i18n="FWC.220f1787581329304" >{{ getLocaleText('FWC.220f1787581329304') }}</span>
1764
1773
  </div>
1765
1774
  <div
1766
1775
  v-for="(item, index) in referenceBidRiskRows(effectiveData as CustomCanvasData).slice(0, 5)"
@@ -1769,8 +1778,8 @@ const {
1769
1778
  :title="nestedBlockItemTitle(item, index)"
1770
1779
  >
1771
1780
  <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>
1781
+ <span class="min-w-0 truncate font-semibold text-slate-600">{{ textValue(item.owner, getLocaleText('FWC.9cb91787581555007')) }}</span>
1782
+ <span class="min-w-0 truncate font-semibold text-slate-700">{{ nestedBlockItemDetail(item) || referenceBidSanitizedMetricValue(item, getLocaleText('FWC.9cb91787581555007')) }}</span>
1774
1783
  </div>
1775
1784
  </div>
1776
1785
  </section>
@@ -1784,16 +1793,16 @@ const {
1784
1793
  >
1785
1794
  <div class="grid grid-cols-[minmax(0,1fr)_auto] items-center gap-2">
1786
1795
  <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>
1796
+ <span :class="nestedBlockPillClasses(item)" :title="referenceBidSanitizedMetricValue(item, getLocaleText('FWC.9cb91787581555007'))">{{ referenceBidSanitizedMetricValue(item, getLocaleText('FWC.9cb91787581555007')) }}</span>
1788
1797
  </div>
1789
- <span class="mt-1 max-h-12 overflow-hidden text-slate-700" :title="nestedBlockItemDetail(item) || referenceBidSanitizedMetricValue(item, '待确认')">{{ nestedBlockItemDetail(item) || referenceBidSanitizedMetricValue(item, '待确认') }}</span>
1798
+ <span class="mt-1 max-h-12 overflow-hidden text-slate-700" :title="nestedBlockItemDetail(item) || referenceBidSanitizedMetricValue(item, getLocaleText('FWC.9cb91787581555007'))">{{ nestedBlockItemDetail(item) || referenceBidSanitizedMetricValue(item, getLocaleText('FWC.9cb91787581555007')) }}</span>
1790
1799
  </div>
1791
1800
  </section>
1792
1801
 
1793
1802
  <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
1803
  <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>
1804
+ <h4 class="truncate text-sm font-semibold leading-5 text-slate-900" data-i18n="FWC.8e081787579902196" >{{ getLocaleText('FWC.8e081787579902196') }}</h4>
1805
+ <p class="mt-1 truncate text-xs font-semibold text-slate-700" data-i18n="FWC.f4a51787578050734" >{{ getLocaleText('FWC.f4a51787578050734') }}</p>
1797
1806
  </div>
1798
1807
  <div class="flex max-w-[32rem] flex-wrap justify-end gap-1.5 overflow-hidden">
1799
1808
  <span
@@ -1802,7 +1811,7 @@ const {
1802
1811
  :class="nestedBlockPillClasses(item)"
1803
1812
  :title="nestedBlockItemTitle(item, index)"
1804
1813
  >
1805
- {{ nestedBlockItemLabel(item, index) }}:{{ referenceBidSanitizedMetricValue(item, '待确认') }}
1814
+ {{ nestedBlockItemLabel(item, index) }}:{{ referenceBidSanitizedMetricValue(item, getLocaleText('FWC.9cb91787581555007')) }}
1806
1815
  </span>
1807
1816
  </div>
1808
1817
  </section>
@@ -1818,7 +1827,7 @@ const {
1818
1827
  >
1819
1828
  <template v-if="businessMetricMatrixLargePanel(effectiveBlock)">
1820
1829
  <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>
1830
+ <h4 class="truncate text-sm font-semibold leading-5 text-slate-900" data-i18n-title="FWC.421a1787581329847" :title="getLocaleText('FWC.421a1787581329847')">{{ getLocaleText('FWC.421a1787581329847') }}</h4>
1822
1831
  <div class="mt-2 grid min-h-0 grid-cols-2 gap-2 overflow-hidden" style="grid-auto-rows: minmax(0, 1fr);">
1823
1832
  <div
1824
1833
  v-for="(item, index) in referenceBusinessMetricItems(effectiveData as CustomCanvasData).slice(0, 4)"
@@ -1846,7 +1855,7 @@ const {
1846
1855
  </section>
1847
1856
  <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
1857
  <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>
1858
+ <h4 class="truncate text-sm font-semibold leading-5 text-slate-900" :title="effectiveBlock.title" data-i18n="FWC.fc641787581330551" >{{ getLocaleText('FWC.fc641787581330551') }}</h4>
1850
1859
  <div class="mt-2 grid min-h-0 content-start gap-2 overflow-hidden">
1851
1860
  <div
1852
1861
  v-for="(item, index) in referenceBusinessChartItems(effectiveData as CustomCanvasData).slice(0, 4)"
@@ -1861,7 +1870,7 @@ const {
1861
1870
  </div>
1862
1871
  </div>
1863
1872
  <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>
1873
+ <h4 class="truncate text-sm font-semibold leading-5 text-slate-900" data-i18n="FWC.c6641787581330910" >{{ getLocaleText('FWC.c6641787581330910') }}</h4>
1865
1874
  <div class="mt-2 grid min-h-0 gap-1 overflow-hidden" style="grid-auto-rows: minmax(0, 1fr);">
1866
1875
  <div
1867
1876
  v-for="(item, index) in referenceBusinessListItems(effectiveData as CustomCanvasData).slice(0, 4)"
@@ -1884,7 +1893,7 @@ const {
1884
1893
  :title="nestedBlockItemTitle(item, index)"
1885
1894
  >
1886
1895
  <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>
1896
+ <span :class="nestedBlockPillClasses(item)" :title="nestedBlockItemValue(item) || nestedBlockItemDetail(item)">{{ nestedBlockItemValue(item) || nestedBlockItemDetail(item) || getLocaleText('FWC.9cb91787581555007') }}</span>
1888
1897
  </div>
1889
1898
  </section>
1890
1899
  </template>
@@ -1903,7 +1912,7 @@ const {
1903
1912
  </div>
1904
1913
  </section>
1905
1914
  <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>
1915
+ <h4 class="truncate text-sm font-semibold leading-5 text-slate-900" :title="effectiveBlock.title" data-i18n="FWC.fc641787581330551" >{{ getLocaleText('FWC.fc641787581330551') }}</h4>
1907
1916
  <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
1917
  <div
1909
1918
  v-for="(item, index) in referenceBusinessChartItems(effectiveData as CustomCanvasData)"
@@ -1917,7 +1926,7 @@ const {
1917
1926
  </div>
1918
1927
  </section>
1919
1928
  <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>
1929
+ <h4 class="truncate text-sm font-semibold leading-5 text-slate-900" data-i18n="FWC.c6641787581330910" >{{ getLocaleText('FWC.c6641787581330910') }}</h4>
1921
1930
  <div class="mt-2 grid min-h-0 gap-1 overflow-hidden" style="grid-auto-rows: minmax(0, 1fr);">
1922
1931
  <div
1923
1932
  v-for="(item, index) in referenceBusinessListItems(effectiveData as CustomCanvasData)"
@@ -1939,7 +1948,7 @@ const {
1939
1948
  :title="nestedBlockItemTitle(item, index)"
1940
1949
  >
1941
1950
  <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>
1951
+ <span :class="nestedBlockPillClasses(item)" :title="nestedBlockItemValue(item) || nestedBlockItemDetail(item)">{{ nestedBlockItemValue(item) || nestedBlockItemDetail(item) || getLocaleText('FWC.9cb91787581555007') }}</span>
1943
1952
  </div>
1944
1953
  </section>
1945
1954
  </template>
@@ -1950,7 +1959,7 @@ const {
1950
1959
  style="grid-template-columns: minmax(0, 1fr) minmax(0, 1.08fr);"
1951
1960
  >
1952
1961
  <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>
1962
+ <h4 class="truncate text-xs font-semibold text-slate-500" data-i18n="FWC.cafe1787579719010" >{{ getLocaleText('FWC.cafe1787579719010') }}</h4>
1954
1963
  <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
1964
  <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
1965
  <span class="min-w-0 truncate text-xs leading-4 text-slate-500" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</span>
@@ -1965,9 +1974,9 @@ const {
1965
1974
  </div>
1966
1975
  </section>
1967
1976
  <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>
1977
+ <h4 class="truncate text-xs font-semibold text-slate-500" data-i18n="FWC.36211787580396613" >{{ getLocaleText('FWC.36211787580396613') }}</h4>
1969
1978
  <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>
1979
+ <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)" data-i18n="FWC.3ba91787581613885" >{{ getLocaleText('FWC.3ba91787581613885') }}</div>
1971
1980
  <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
1981
  <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
1982
  <span class="truncate text-slate-500" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</span>
@@ -1988,12 +1997,12 @@ const {
1988
1997
  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
1998
  >
1990
1999
  <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>
2000
+ <h4 class="truncate text-xs font-semibold text-slate-500" data-i18n="FWC.4bec1787580564702" >{{ getLocaleText('FWC.4bec1787580564702') }}</h4>
1992
2001
  <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) || '正常'}`">
2002
+ <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) || getLocaleText('FWC.94c31787581614130')}`">
1994
2003
  <i :class="nestedBlockDotClasses(item)" />
1995
2004
  <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>
2005
+ <span :class="nestedBlockPillClasses(item)" :title="nestedBlockItemValue(item) || getLocaleText('FWC.94c31787581614130')">{{ nestedBlockItemValue(item) || getLocaleText('FWC.94c31787581614130') }}</span>
1997
2006
  </div>
1998
2007
  </div>
1999
2008
  <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));">
@@ -2005,7 +2014,7 @@ const {
2005
2014
  </div>
2006
2015
  </section>
2007
2016
  <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>
2017
+ <h4 class="truncate text-xs font-semibold text-slate-500" data-i18n="FWC.49d41787579902282" >{{ getLocaleText('FWC.49d41787579902282') }}</h4>
2009
2018
  <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
2019
  <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
2020
  <span
@@ -2026,14 +2035,14 @@ const {
2026
2035
  </div>
2027
2036
  <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
2037
  <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>
2038
+ <span class="truncate font-semibold text-slate-500" data-i18n="FWC.f4821787580396721" >{{ getLocaleText('FWC.f4821787580396721') }}</span>
2039
+ <b class="text-slate-800" data-i18n="FWC.722e1787580396835" >{{ getLocaleText('FWC.722e1787580396835') }}</b>
2031
2040
  </div>
2032
2041
  <div class="grid min-h-0 grid-cols-7 items-stretch gap-1 overflow-hidden">
2033
2042
  <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
2043
  <b class="truncate text-slate-700">{{ nestedBlockItemValue(item) || nestedBlockItemLabel(item, index) }}</b>
2035
2044
  <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>
2045
+ <span class="truncate">{{ nestedBlockItemValue(item) ? nestedBlockItemLabel(item, index) : getLocaleText('FWC.0f961787579902556', {p0: index + 1}) }}</span>
2037
2046
  </div>
2038
2047
  </div>
2039
2048
  </div>
@@ -2044,7 +2053,7 @@ const {
2044
2053
  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
2054
  >
2046
2055
  <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>
2056
+ <h4 class="truncate text-xs font-semibold text-slate-500" data-i18n="FWC.40151787580565226" >{{ getLocaleText('FWC.40151787580565226') }}</h4>
2048
2057
  <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
2058
  <div class="workbench-reference-security-score-main grid min-h-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-2">
2050
2059
  <div class="min-w-0 flex items-end gap-1">
@@ -2068,7 +2077,7 @@ const {
2068
2077
  </div>
2069
2078
  </section>
2070
2079
  <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>
2080
+ <h4 class="truncate text-xs font-semibold text-slate-500" data-i18n="FWC.09341787581068920" >{{ getLocaleText('FWC.09341787581068920') }}</h4>
2072
2081
  <div class="workbench-reference-security-compliance-list grid h-full min-h-0 gap-1 overflow-hidden">
2073
2082
  <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
2083
  <span class="min-w-0 truncate font-semibold text-slate-800" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</span>
@@ -2083,7 +2092,7 @@ const {
2083
2092
  style="grid-template-columns: minmax(0, 1.16fr) minmax(0, 0.84fr);"
2084
2093
  >
2085
2094
  <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>
2095
+ <h4 class="truncate text-xs font-semibold text-slate-500" data-i18n="FWC.0deb1787579719092" >{{ getLocaleText('FWC.0deb1787579719092') }}</h4>
2087
2096
  <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
2097
  <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
2098
  <span class="min-w-0 truncate font-semibold text-slate-800">{{ nestedBlockItemLabel(item, index) }}</span>
@@ -2099,7 +2108,7 @@ const {
2099
2108
  </div>
2100
2109
  </section>
2101
2110
  <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>
2111
+ <h4 class="truncate text-xs font-semibold text-slate-500" data-i18n="FWC.bd2d1787580396946" >{{ getLocaleText('FWC.bd2d1787580396946') }}</h4>
2103
2112
  <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
2113
  <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
2114
  <strong class="workbench-reference-metric-value max-w-full truncate text-sm leading-none text-slate-900">{{ nestedBlockItemValue(item) }}</strong>
@@ -2141,16 +2150,16 @@ const {
2141
2150
  <text x="12" y="55" text-anchor="start" font-size="7" font-weight="700" class="fill-slate-500">合规安全</text>
2142
2151
  </svg>
2143
2152
  <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>
2153
+ <span class="rounded border border-red-100 bg-red-50 px-1.5 py-1 font-semibold text-red-600" data-i18n="FWC.4dd11787580565750" >{{ getLocaleText('FWC.4dd11787580565750') }}</span>
2154
+ <span class="rounded border border-amber-100 bg-amber-50 px-1.5 py-1 font-semibold text-amber-700" data-i18n="FWC.ea401787580566275" >{{ getLocaleText('FWC.ea401787580566275') }}</span>
2155
+ <span class="rounded border border-slate-100 bg-white px-1.5 py-1 font-semibold text-slate-500" data-i18n="FWC.33861787581069054" >{{ getLocaleText('FWC.33861787581069054') }}</span>
2147
2156
  </div>
2148
2157
  </section>
2149
2158
  <section class="workbench-reference-health-radar-risk-list grid min-h-0 content-start gap-2 overflow-hidden">
2150
2159
  <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
2160
  <strong class="block truncate text-sm leading-5 text-slate-900" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</strong>
2152
2161
  <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>
2162
+ <span :class="['mt-1 inline-flex max-w-full truncate', nestedBlockPillClasses(item)]" :title="nestedBlockItemValue(item) || getLocaleText('FWC.22f81787581615624')">{{ nestedBlockItemValue(item) || getLocaleText('FWC.22f81787581615624') }}</span>
2154
2163
  </div>
2155
2164
  </section>
2156
2165
  </div>
@@ -2160,8 +2169,8 @@ const {
2160
2169
  >
2161
2170
  <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
2171
  <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) }}
2172
+ <span v-for="(item, index) in referenceDeviationBars(effectiveData as CustomCanvasData)" :key="`deviation-target-${index}`" class="truncate" :title="nestedBlockItemValue(item) || getLocaleText('FWC.db771787581616143')" data-i18n="FWC.3f911787579587268" >
2173
+ {{ getLocaleText('FWC.3f911787579587268', {p0: nestedBlockItemValue(item)}) }}
2165
2174
  </span>
2166
2175
  </div>
2167
2176
  <div class="relative grid min-h-0 grid-cols-6 items-end gap-1 overflow-hidden px-3">
@@ -2182,7 +2191,7 @@ const {
2182
2191
  <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
2192
  <strong class="shrink-0 truncate text-sm leading-5 text-red-700" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</strong>
2184
2193
  <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>
2194
+ <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) || getLocaleText('FWC.35141787581331279')">{{ nestedBlockItemValue(item) || getLocaleText('FWC.35141787581331279') }}</span>
2186
2195
  </div>
2187
2196
  </section>
2188
2197
  </div>
@@ -2220,7 +2229,7 @@ const {
2220
2229
  <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
2230
  <strong class="block truncate text-sm leading-5 text-red-700" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</strong>
2222
2231
  <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>
2232
+ <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) || getLocaleText('FWC.d96a1787580397126')">{{ nestedBlockItemValue(item) || getLocaleText('FWC.d96a1787580397126') }}</span>
2224
2233
  </div>
2225
2234
  </section>
2226
2235
  </div>
@@ -2283,11 +2292,11 @@ const {
2283
2292
  <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
2293
  <strong class="block truncate text-sm leading-5 text-amber-800" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</strong>
2285
2294
  <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>
2295
+ <span :class="['mt-1 inline-flex max-w-full truncate', nestedBlockPillClasses(item)]" :title="nestedBlockItemValue(item) || getLocaleText('FWC.9c8c1787581069191')">{{ nestedBlockItemValue(item) || getLocaleText('FWC.9c8c1787581069191') }}</span>
2287
2296
  </div>
2288
2297
  <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>
2298
+ <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" data-i18n="FWC.f2291787581332024" >{{ getLocaleText('FWC.f2291787581332024') }}</span>
2299
+ <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" data-i18n="FWC.b35c1787581332213" >{{ getLocaleText('FWC.b35c1787581332213') }}</span>
2291
2300
  </div>
2292
2301
  </section>
2293
2302
  </div>
@@ -2299,9 +2308,9 @@ const {
2299
2308
  <div class="min-w-0">
2300
2309
  <strong class="block truncate text-sm leading-5 text-slate-900" :title="nestedBlockItemTitle(item, index)">{{ nestedBlockItemLabel(item, index) }}</strong>
2301
2310
  <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>
2311
+ <span class="truncate" :title="referenceExecutiveTodoImpact(item, index)" data-i18n="FWC.2c581787579587328" >{{ getLocaleText('FWC.2c581787579587328', {p0: referenceExecutiveTodoImpact(item, index)}) }}</span>
2312
+ <span class="truncate" :title="referenceExecutiveTodoDeadline(item, index)" data-i18n="FWC.14831787579587388" >{{ getLocaleText('FWC.14831787579587388', {p0: referenceExecutiveTodoDeadline(item, index)}) }}</span>
2313
+ <span class="truncate" :title="referenceExecutiveTodoProgress(item, index)" data-i18n="FWC.b3241787579587453" >{{ getLocaleText('FWC.b3241787579587453', {p0: referenceExecutiveTodoProgress(item, index)}) }}</span>
2305
2314
  </div>
2306
2315
  </div>
2307
2316
  <span :class="referenceExecutiveTodoBadgeClasses(item, index)" :title="referenceExecutiveTodoBadge(item, index)">{{ referenceExecutiveTodoBadge(item, index) }}</span>
@@ -2381,22 +2390,22 @@ const {
2381
2390
  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
2391
  data-nested-business-gap-action-label="true"
2383
2392
  :title="nestedBlockFailureReason(nestedBlock)"
2384
- aria-label="需补充业务口径"
2393
+ data-i18n-aria-label="FWC.cc9b1787580395753" :aria-label="getLocaleText('FWC.cc9b1787580395753')" data-i18n="FWC.c26c1787580015097"
2385
2394
  >
2386
- 子卡 · 补口径
2395
+ {{ getLocaleText('FWC.c26c1787580015097') }}
2387
2396
  </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
- 子卡
2397
+ <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']" data-i18n="FWC.37c41787581616401" >
2398
+ {{ getLocaleText('FWC.37c41787581616401') }}
2390
2399
  </span>
2391
2400
  </div>
2392
2401
  <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>
2402
+ <div v-if="nestedBlockNeedsHumanIntervention(nestedBlock)" class="mb-1 font-semibold text-amber-700">{{ getLocaleText('FWC.cc9b1787580395753') }}</div>
2394
2403
  <div class="line-clamp-2 font-medium" :title="nestedBlockFailureReason(nestedBlock)">{{ nestedBlockFailureReason(nestedBlock) }}</div>
2395
2404
  <div class="mt-0.5 line-clamp-1 text-rose-600" :title="nestedBlockQueryIntent(nestedBlock)">{{ nestedBlockQueryIntent(nestedBlock) }}</div>
2396
2405
  </div>
2397
2406
  <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>
2407
+ <span class="min-w-0 truncate text-slate-500" data-i18n="FWC.24a11787579281944" >{{ getLocaleText('FWC.24a11787579281944') }}</span>
2408
+ <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" data-i18n="FWC.09361787581554284" >{{ getLocaleText('FWC.09361787581554284') }}</span>
2400
2409
  </div>
2401
2410
  <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
2411
  <div class="workbench-nested-status-summary grid grid-cols-3 gap-1">
@@ -2408,7 +2417,7 @@ const {
2408
2417
  <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
2418
  <i :class="nestedBlockDotClasses(item)" />
2410
2419
  <span class="min-w-0 truncate font-semibold text-slate-800">{{ nestedBlockItemLabel(item, index) }}</span>
2411
- <span :class="nestedBlockPillClasses(item)">{{ nestedBlockItemValue(item) || '正常' }}</span>
2420
+ <span :class="nestedBlockPillClasses(item)">{{ nestedBlockItemValue(item) || getLocaleText('FWC.94c31787581614130') }}</span>
2412
2421
  </div>
2413
2422
  </div>
2414
2423
  <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">
@@ -2438,8 +2447,8 @@ const {
2438
2447
  </div>
2439
2448
  <div v-else-if="nestedBlockVisualKind(nestedBlock) === 'securityScore'" class="workbench-nested-security-score mt-1 rounded-md bg-[#101820] p-2 text-white">
2440
2449
  <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>
2450
+ <span class="truncate text-xs text-slate-300" data-i18n="FWC.9f2e1787581069492" >{{ getLocaleText('FWC.9f2e1787581069492') }}</span>
2451
+ <span class="rounded-full border border-amber-200 bg-amber-50 px-2 py-0.5 text-xs font-semibold text-amber-700" data-i18n="FWC.130e1787581558902" >{{ getLocaleText('FWC.130e1787581558902') }}</span>
2443
2452
  </div>
2444
2453
  <div class="mt-2 grid grid-cols-[minmax(0,1fr)_4rem] items-center gap-2">
2445
2454
  <div class="min-w-0">
@@ -2461,7 +2470,7 @@ const {
2461
2470
  <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
2471
  <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
2472
  <span class="min-w-0 truncate font-semibold text-slate-800">{{ nestedBlockItemLabel(item, index) }}</span>
2464
- <span :class="nestedBlockPillClasses(item)">{{ nestedBlockItemValue(item) || '待确认' }}</span>
2473
+ <span :class="nestedBlockPillClasses(item)">{{ nestedBlockItemValue(item) || getLocaleText('FWC.9cb91787581555007') }}</span>
2465
2474
  </div>
2466
2475
  </div>
2467
2476
  <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">
@@ -2490,7 +2499,7 @@ const {
2490
2499
  </div>
2491
2500
  </div>
2492
2501
  <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>
2502
+ <div class="grid h-16 w-16 place-items-center rounded-full text-xs font-semibold text-slate-500" :style="nestedBlockDonutStyle(nestedBlock)" data-i18n="FWC.fe091787581332411" >{{ getLocaleText('FWC.fe091787581332411') }}</div>
2494
2503
  <div class="grid min-w-0 gap-1 text-xs">
2495
2504
  <div v-for="(item, index) in nestedBlockDonutItems(nestedBlock)" :key="`${nestedBlock.id}-donut-${index}`" class="grid grid-cols-[minmax(0,1fr)_auto] gap-1">
2496
2505
  <span class="truncate text-slate-500">{{ nestedBlockItemLabel(item, index) }}</span>
@@ -2527,9 +2536,9 @@ const {
2527
2536
  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
2537
  >
2529
2538
  <div class="min-w-0">
2530
- <span class="block truncate text-slate-500">保留截图区域,等待可用业务口径</span>
2539
+ <span class="block truncate text-slate-500" data-i18n="FWC.24a11787579281944" >{{ getLocaleText('FWC.24a11787579281944') }}</span>
2531
2540
  </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>
2541
+ <span class="shrink-0 rounded-full border border-slate-200 bg-white px-2 py-0.5 font-semibold leading-5 text-slate-500" data-i18n="FWC.09361787581554284" >{{ getLocaleText('FWC.09361787581554284') }}</span>
2533
2542
  </div>
2534
2543
  <div v-if="customCanvasOverlaysVisibleElements(effectiveBlock, effectiveData as CustomCanvasData)" class="pointer-events-none absolute inset-0 overflow-hidden">
2535
2544
  <template v-for="element in customCanvasVisibleElements(effectiveBlock, effectiveData as CustomCanvasData)" :key="element.id">
@@ -2568,8 +2577,8 @@ const {
2568
2577
  <div :class="manualReplacementShellClasses(effectiveBlock)" :style="manualReplacementContainerStyle(effectiveBlock)">
2569
2578
  <div class="min-h-0 flex-1 space-y-1 overflow-y-auto pr-1">
2570
2579
  <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>
2580
+ <div class="inline-flex rounded-full bg-white px-2.5 py-0.5 text-xs font-semibold text-amber-700" data-i18n="FWC.5fa41787581069631" >{{ getLocaleText('FWC.5fa41787581069631') }}</div>
2581
+ <div class="truncate text-sm font-semibold leading-5 text-slate-900" :title="effectiveBlock.title || getLocaleText('FWC.b4b91787581069769')">{{ effectiveBlock.title || getLocaleText('FWC.b4b91787581069769') }}</div>
2573
2582
  <p class="line-clamp-1 text-xs leading-5 text-amber-800" :title="manualReplacementView(effectiveBlock)?.reason">{{ manualReplacementView(effectiveBlock)?.reason }}</p>
2574
2583
  <p v-if="manualReplacementCompactView(effectiveBlock)" class="truncate text-xs font-medium text-amber-700" :title="manualReplacementView(effectiveBlock)?.suggestedCapabilityLabel || manualReplacementView(effectiveBlock)?.suggestedKindLabel">
2575
2584
  {{ manualReplacementView(effectiveBlock)?.suggestedCapabilityLabel || manualReplacementView(effectiveBlock)?.suggestedKindLabel }}
@@ -2577,23 +2586,23 @@ const {
2577
2586
  </div>
2578
2587
  <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
2588
  <div class="min-w-0 rounded-md bg-white px-2 py-1">
2580
- <div class="text-slate-400">建议类型</div>
2589
+ <div class="text-slate-400" data-i18n="FWC.70091787581332606" >{{ getLocaleText('FWC.70091787581332606') }}</div>
2581
2590
  <div class="mt-0.5 font-semibold text-slate-800">{{ manualReplacementView(effectiveBlock)?.suggestedKindLabel }}</div>
2582
2591
  <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
2592
  </div>
2584
2593
  <div class="min-w-0 rounded-md bg-white px-2 py-1">
2585
- <div class="text-slate-400">置信度</div>
2594
+ <div class="text-slate-400" data-i18n="FWC.2f881787581559140" >{{ getLocaleText('FWC.2f881787581559140') }}</div>
2586
2595
  <div class="mt-0.5 font-semibold text-slate-800">{{ manualReplacementView(effectiveBlock)?.confidenceLabel }}</div>
2587
2596
  </div>
2588
2597
  <div class="min-w-0 rounded-md bg-white px-2 py-1">
2589
- <div class="text-slate-400">截图区域</div>
2598
+ <div class="text-slate-400" data-i18n="FWC.cdff1787581332800" >{{ getLocaleText('FWC.cdff1787581332800') }}</div>
2590
2599
  <div class="mt-0.5 truncate font-semibold text-slate-800">{{ manualReplacementView(effectiveBlock)?.regionLabel }}</div>
2591
2600
  </div>
2592
2601
  </div>
2593
2602
  </div>
2594
2603
  <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
2604
  <label v-if="!manualReplacementCompactView(effectiveBlock)" class="min-w-0 text-xs font-medium text-amber-900">
2596
- <span class="sr-only">替换卡片</span>
2605
+ <span class="sr-only" data-i18n="FWC.07471787581332988" >{{ getLocaleText('FWC.07471787581332988') }}</span>
2597
2606
  <select
2598
2607
  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
2608
  :value="manualReplacementCapabilityDraft(effectiveBlock)"
@@ -2626,22 +2635,22 @@ const {
2626
2635
  </template>
2627
2636
 
2628
2637
  <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 || '未命名卡片' }}
2638
+ {{ effectiveBlock.title || getLocaleText('FWC.ecf41787581070050') }}
2630
2639
  </div>
2631
2640
  </template>
2632
2641
 
2633
2642
  <template v-else-if="effectiveBlock.blockType === 'form' && isFormBlockData(effectiveBlock.form)">
2634
2643
  <div class="space-y-4 overflow-y-auto">
2635
2644
  <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>
2645
+ <span>草稿状态:{{ effectiveBlock.form.status === 'submitted' ? getLocaleText('FWC.e6051787581559368') : getLocaleText('FWC.20551787581559847') }}</span>
2646
+ <span data-i18n="FWC.86291787579127440" >{{ getLocaleText('FWC.86291787579127440', {p0: formCompletedCount(effectiveBlock.id, effectiveBlock.form),p1: effectiveBlock.form.fields.length}) }}</span>
2638
2647
  </div>
2639
2648
  <div class="space-y-4">
2640
2649
  <label v-for="field in compactLimit(effectiveBlock.form.fields, 2, 3)" :key="field.id" class="block space-y-2">
2641
2650
  <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
2651
  <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
2652
  <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>
2653
+ <option value="">{{ field.type === 'user' ? getLocaleText('FWC.8b821787581070199') : getLocaleText('FWC.cd181787581560088') }}</option>
2645
2654
  <option v-for="option in field.options || []" :key="option" :value="option">{{ option }}</option>
2646
2655
  </select>
2647
2656
  <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" />
@@ -2649,8 +2658,9 @@ const {
2649
2658
  </div>
2650
2659
  <div class="flex justify-end">
2651
2660
  <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>
2661
+ <Send class="mr-2 h-4 w-4" />
2662
+ <span data-i18n="FWC.6a3a1787581333240" >{{ getLocaleText('FWC.6a3a1787581333240') }}</span>
2663
+ </button>
2654
2664
  </div>
2655
2665
  </div>
2656
2666
  </template>
@@ -2658,13 +2668,13 @@ const {
2658
2668
  <template v-else-if="effectiveBlock.blockType === 'survey' && isSurveyBlockData(effectiveBlock.survey)">
2659
2669
  <div class="space-y-5 overflow-y-auto">
2660
2670
  <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>
2671
+ <span data-i18n="FWC.1e241787579139103" >{{ getLocaleText('FWC.1e241787579139103', {p0: effectiveBlock.survey.progress.current,p1: effectiveBlock.survey.progress.total}) }}</span>
2672
+ <span>{{ effectiveBlock.survey.status === 'submitted' ? getLocaleText('FWC.e6051787581559368') : getLocaleText('FWC.e1de1787581560318') }}</span>
2663
2673
  </div>
2664
2674
  <div class="space-y-4">
2665
2675
  <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
2676
  <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="请输入补充说明" />
2677
+ <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" data-i18n-placeholder="FWC.adb61787580397364" :placeholder="getLocaleText('FWC.adb61787580397364')" />
2668
2678
  <div v-else-if="question.type === 'score'" class="flex flex-wrap gap-2">
2669
2679
  <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
2680
  </div>
@@ -2681,7 +2691,9 @@ const {
2681
2691
  </div>
2682
2692
  </div>
2683
2693
  </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>
2694
+ <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" />
2695
+ <span data-i18n="FWC.ddf91787581333428" >{{ getLocaleText('FWC.ddf91787581333428') }}</span>
2696
+ </button></div>
2685
2697
  </div>
2686
2698
  </template>
2687
2699
 
@@ -2703,7 +2715,7 @@ const {
2703
2715
  <div class="space-y-4">
2704
2716
  <div v-for="(step, index) in compactLimit(effectiveBlock.workflow.steps, 2, 4)" :key="`${step.time}-${step.label}`" class="flex gap-4">
2705
2717
  <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>
2718
+ <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 || getLocaleText('FWC.70f91787581616730') }}</div><div v-if="step.description" class="mt-2 text-xs leading-5 text-slate-400">{{ step.description }}</div></div>
2707
2719
  </div>
2708
2720
  </div>
2709
2721
  </div>
@@ -2712,8 +2724,10 @@ const {
2712
2724
  <template v-else-if="effectiveBlock.blockType === 'report' && isReportBlockData(effectiveBlock.report)">
2713
2725
  <div class="space-y-5 overflow-y-auto">
2714
2726
  <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>
2727
+ <div><div class="text-xs uppercase text-blue-100">Report Artifact</div><div class="mt-2 text-2xl font-semibold" data-i18n="FWC.cf3a1787579239372" >{{ getLocaleText('FWC.cf3a1787579239372', {p0: effectiveBlock.report.version}) }}</div><p class="mt-3 max-w-2xl text-sm leading-6 text-blue-50">{{ effectiveBlock.report.summary }}</p></div>
2728
+ <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" />
2729
+ <span data-i18n="FWC.53381787581070339" >{{ getLocaleText('FWC.53381787581070339') }}</span>
2730
+ </button>
2717
2731
  </div>
2718
2732
  <div class="grid gap-4 lg:grid-cols-3">
2719
2733
  <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>
@@ -2722,7 +2736,7 @@ const {
2722
2736
  </template>
2723
2737
 
2724
2738
  <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 || '暂未匹配渲染器' }}
2739
+ {{ effectiveBlock.title || getLocaleText('FWC.948d1787580397492') }}
2726
2740
  </div>
2727
2741
  </div>
2728
2742
  </template>