@mx-sose-front/mx-sose-graph 1.2.1 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/index.esm.js +1525 -1157
  2. package/dist/index.esm.js.map +1 -1
  3. package/dist/index.umd.js +1 -1
  4. package/dist/index.umd.js.map +1 -1
  5. package/dist/style.css +1 -1
  6. package/package.json +1 -1
  7. package/src/components/Gantt/Gantt.vue +2 -0
  8. package/src/components/Matrix/Matrix.vue +87 -12
  9. package/src/components/MatrixContextMenu/MatrixContextMenu.vue +235 -0
  10. package/src/components/Shape/DividingLine.vue +80 -64
  11. package/src/components/Table/Table.vue +2 -0
  12. package/src/constants/edgeShapeKeys.ts +4 -2
  13. package/src/constants/index.ts +18 -10
  14. package/src/hooks/useChartRowSelection.ts +37 -6
  15. package/src/statics/icons/childIcons/DIV-3/347/211/251/347/220/206/346/225/260/346/215/256/346/250/241/345/236/213/345/233/276@3x.png +0 -0
  16. package/src/statics/icons/childIcons/SV-3/347/263/273/347/273/237/342/200/224/347/263/273/347/273/237/347/237/251/351/230/265/345/214/205@3x.png +0 -0
  17. package/src/statics/icons/childIcons/SvcV-10c/346/234/215/345/212/241/344/272/213/344/273/266/342/200/224/350/277/275/350/270/252/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  18. package/src/statics/icons/childIcons/SvcV-2 /346/234/215/345/212/241/350/265/204/346/272/220/346/265/201/345/206/205/351/203/250/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  19. package/src/statics/icons/childIcons/SvcV-3a/347/263/273/347/273/237/342/200/224/346/234/215/345/212/241/347/237/251/351/230/265/345/214/205@3x.png +0 -0
  20. package/src/statics/icons/childIcons/SvcV-3b /346/234/215/345/212/241 -/346/234/215/345/212/241/347/237/251/351/230/265@3x.png +0 -0
  21. package/src/statics/icons/childIcons/SvcV-3b/346/234/215/345/212/241/342/200/224/346/234/215/345/212/241/347/237/251/351/230/265/345/214/205@3x.png +0 -0
  22. package/src/statics/icons/childIcons/SvcV-5 /346/234/215/345/212/241/345/210/260/344/270/232/345/212/241/346/264/273/345/212/250/345/217/257/350/277/275/346/272/257/346/200/247/347/237/251/351/230/265@3x.png +0 -0
  23. package/src/statics/icons/childIcons/set@3x.png +0 -0
  24. package/src/statics/icons/childIcons//344/270/232/345/212/241/345/261/202@3x.png +0 -0
  25. package/src/statics/icons/childIcons//344/270/232/345/212/241/346/211/247/350/241/214/350/200/205/344/270/216/350/203/275/345/212/233/346/230/240/345/260/204/347/237/251/351/230/265@3x.png +0 -0
  26. package/src/statics/icons/childIcons//344/270/232/345/212/241/347/273/223/346/236/204/345/233/276@3x.png +0 -0
  27. package/src/statics/icons/childIcons//344/270/232/345/212/241/347/274/223/350/247/243/346/216/252/346/226/275@3x.png +0 -0
  28. package/src/statics/icons/childIcons//344/272/272/345/221/230/345/261/202@3x.png +0 -0
  29. package/src/statics/icons/childIcons//344/272/272/345/221/230/347/272/246/346/235/237/345/256/232/344/271/211/345/233/276@3x.png +0 -0
  30. package/src/statics/icons/childIcons//345/256/211/345/205/250/345/261/202@3x.png +0 -0
  31. package/src/statics/icons/childIcons//345/256/236/351/231/205/346/210/230/347/225/245/351/230/266/346/256/265/344/270/216/350/203/275/345/212/233/346/230/240/345/260/204/347/237/251/351/230/265@3x.png +0 -0
  32. package/src/statics/icons/childIcons//345/256/236/351/231/205/350/265/204/346/272/220/345/205/263/347/263/273@3x.png +0 -0
  33. package/src/statics/icons/childIcons//345/256/236/351/231/205/350/265/204/346/272/220/345/261/202@3x.png +0 -0
  34. package/src/statics/icons/childIcons//346/210/230/347/225/245/345/261/202@3x.png +0 -0
  35. package/src/statics/icons/childIcons//346/234/215/345/212/241/345/261/202@3x.png +0 -0
  36. package/src/statics/icons/childIcons//346/234/215/345/212/241/350/277/236/351/200/232/347/237/251/351/230/265@3x.png +0 -0
  37. package/src/statics/icons/childIcons//346/234/215/345/212/241/350/277/236/351/200/232/350/241/250@3x.png +0 -0
  38. package/src/statics/icons/childIcons//346/240/207/345/207/206/345/261/202@3x.png +0 -0
  39. package/src/statics/icons/childIcons//346/240/207/345/207/206/350/267/257/347/272/277/350/241/250@3x.png +0 -0
  40. package/src/statics/icons/childIcons//346/240/207/345/207/206/350/277/275/346/272/257/350/241/250@3x.png +0 -0
  41. package/src/statics/icons/childIcons//347/212/266/346/200/201/346/214/207/346/240/207@3x.png +0 -0
  42. package/src/statics/icons/childIcons//350/265/204/346/272/220/345/261/202@3x.png +0 -0
  43. package/src/statics/icons/childIcons//351/200/202/347/224/250/350/203/275/345/212/233@3x.png +0 -0
  44. package/src/statics/icons/childIcons//351/241/271/347/233/256/345/261/202@3x.png +0 -0
  45. package/src/utils/keyboardUtils.ts +13 -0
  46. /package/src/statics/icons/childIcons/{role@3x.png → Role@3x.png} +0 -0
  47. /package/src/statics/icons/childIcons/SV-10c/347/263/273/347/273/237/344/272/213/344/273/{266- → 266/342/200/224}/350/277/275/350/270/252/346/217/217/350/277/260/345/214/205@3x.png" +0 -0
  48. /package/src/statics/icons/childIcons/{SV-3/347/263/273/347/273/237-/347/263/273/347/273/237/347/237/251/351/230/265 → SV-10c/347/263/273/347/273/237/344/272/213/344/273/266/344/270/200/350/277/275/350/270/252/346/217/217/350/277/260}/345/214/205@3x.png" +0 -0
  49. /package/src/statics/icons/childIcons//347/233/270/346/257/{224@3x (1).png" → 224@3x.png"} +0 -0
@@ -198,6 +198,8 @@ const headerHeight = computed(() => {
198
198
 
199
199
  // 响应式状态管理
200
200
  const actualContentHeight = ref<number>(0); // 实际内容高度
201
+ // 实际内容宽度
202
+ const actualContentWidth = ref<number>(0)
201
203
  const contentRef = ref<HTMLElement | null>(null);
202
204
 
203
205
  // 内容区域高度计算
@@ -278,73 +280,90 @@ const reportMetrics = () => {
278
280
  });
279
281
  }
280
282
 
281
- // 测量实际内容高度并更新组件
282
- const measureContentHeight = () => {
283
- if (!contentRef.value) return;
283
+ /**
284
+ * 测量内容真实宽高
285
+ */
286
+ const measureContentSize = () => {
287
+ if (!contentRef.value) return
288
+
289
+ // 先重置,保证测量的是内容自然撑开的尺寸
290
+ contentRef.value.style.width = 'auto'
291
+ contentRef.value.style.height = 'auto'
292
+ contentRef.value.style.maxWidth = 'none'
293
+
294
+ // 真实内容尺寸
295
+ const realWidth = contentRef.value.scrollWidth
296
+ const realHeight = contentRef.value.scrollHeight
297
+
298
+ let changed = false
299
+
300
+ if (realWidth !== actualContentWidth.value) {
301
+ actualContentWidth.value = realWidth
302
+ changed = true
303
+ }
284
304
 
285
- // 强制重新计算内容尺寸,特别是在宽度变化的情况下
286
- contentRef.value.style.width = '100%'; // 确保内容区域宽度正确
287
- contentRef.value.style.height = 'auto'; // 重置高度以测量实际需要的高度
305
+ if (realHeight !== actualContentHeight.value) {
306
+ actualContentHeight.value = realHeight
307
+ changed = true
308
+ }
288
309
 
289
- // 获取实际内容高度
290
- const actualHeight = contentRef.value.scrollHeight;
291
- if (actualHeight !== actualContentHeight.value) {
292
- actualContentHeight.value = actualHeight;
310
+ if (changed) {
293
311
  nextTick(() => {
294
312
  updateShapeBounds()
295
313
  debouncedReportMetrics()
296
314
  })
297
-
298
315
  }
299
- };
316
+ }
300
317
 
301
318
  // 更新组件宽度和高度
319
+ /**
320
+ * 更新组件宽高
321
+ */
302
322
  const updateShapeBounds = () => {
303
- // 计算内容所需的最小总高度
304
- const minTotalHeight = headerHeight.value + 15 + contentHeight.value + 10; // 加上一些额外空间
323
+ // 内容区左右 padding:foreignObject x=12,左右一共约 24
324
+ const contentRequiredWidth = actualContentWidth.value > 0
325
+ ? actualContentWidth.value + 24
326
+ : 0
327
+
328
+ // 标题区和内容区,取最大值
329
+ const requiredWidth = Math.max(
330
+ estimatedTextWidth.value,
331
+ contentRequiredWidth,
332
+ 150
333
+ )
334
+
335
+ // 计算最小总高度
336
+ const minTotalHeight = headerHeight.value + 15 + contentHeight.value + 10
305
337
 
306
- // 设置一个基于字体大小的最小高度,确保字体较大时组件也能正常显示
307
338
  const fontSizeBasedMinHeight = Math.max(
308
339
  (keywordsStyle.value.fontSize || 12) * 3,
309
340
  (nameStyle.value.fontSize || 12) * 3
310
- ) + 50; // 基于字体大小的最小高度 + 内容区域基本高度
311
-
312
- // 设置一个明确的最小高度限制,确保组件不会太小
313
- const explicitMinHeight = 110; // 明确的最小高度值,不小于100
314
- const effectiveMinHeight = Math.max(minTotalHeight, fontSizeBasedMinHeight, explicitMinHeight);
341
+ ) + 50
315
342
 
316
- // 获取当前组件尺寸
317
- const currentWidth = props.shape.bounds?.width || 0;
318
- const currentHeight = props.shape.bounds?.height || 0;
343
+ const explicitMinHeight = 110
344
+ const effectiveMinHeight = Math.max(
345
+ minTotalHeight,
346
+ fontSizeBasedMinHeight,
347
+ explicitMinHeight
348
+ )
319
349
 
320
- // 获取所需宽度,确保包含文本内容和图标
321
- const requiredWidth = Math.max(estimatedTextWidth.value, 120); // 确保至少有120的宽度
350
+ const currentWidth = props.shape.bounds?.width || 0
351
+ const currentHeight = props.shape.bounds?.height || 0
322
352
 
323
- // 准备更新的属性
324
- const updates: any = {};
353
+ const nextWidth = Math.max(currentWidth, requiredWidth)
354
+ const nextHeight = Math.max(currentHeight, effectiveMinHeight)
325
355
 
326
- // 重要:无论是否在缩放中,都确保组件高度至少达到有效最小高度
327
- // 这可以防止预览框在缩放过程中变得太小
328
- if (currentHeight < effectiveMinHeight) {
329
- updates.height = effectiveMinHeight;
330
- }
356
+ // 宽高没变就不更新,避免死循环
357
+ if (nextWidth === currentWidth && nextHeight === currentHeight) return
331
358
 
332
- // 无论是否在缩放中,都确保宽度至少达到所需宽度
333
- // 这可以防止缩小时预览框右边不显示
334
- if (currentWidth < requiredWidth) {
335
- updates.width = requiredWidth;
336
- }
337
-
338
- // 如果有更新,则应用
339
- if (Object.keys(updates).length > 0) {
340
- graphStore.updateShape(props.shape.id, {
341
- bounds: {
342
- ...props.shape.bounds,
343
- ...updates
344
- }
345
- });
346
- }
347
- };
359
+ graphStore.updateShape(props.shape.id, {
360
+ bounds: {
361
+ ...props.shape.bounds,
362
+ width: nextWidth,
363
+ height: nextHeight
364
+ }
365
+ })
366
+ }
348
367
 
349
368
  // 添加额外的尺寸保护,在拖拽结束后强制检查最小尺寸
350
369
  const enforceMinSizeOnResizeEnd = () => {
@@ -389,7 +408,7 @@ const debouncedUpdateShapeBounds = debounce(updateShapeBounds, 100);
389
408
 
390
409
  // 监听尺寸变化,更新compartment区域
391
410
  const debouncedReportMetrics = debounce(reportMetrics, 100);
392
- const debouncedMeasureContentHeight = debounce(measureContentHeight, 100);
411
+ const debouncedMeasureContentSize = debounce(measureContentSize, 100)
393
412
 
394
413
  // 监听拖拽缩放事件
395
414
  const handleDragStart = () => {
@@ -407,7 +426,7 @@ onMounted(() => {
407
426
  nextTick(() => {
408
427
  reportMetrics();
409
428
  // 初始测量内容高度
410
- setTimeout(measureContentHeight, 0);
429
+ setTimeout(measureContentSize, 0)
411
430
  // 初始更新图元尺寸
412
431
  updateShapeBounds();
413
432
  });
@@ -419,7 +438,7 @@ onMounted(() => {
419
438
  eventBus.on('shape-resize-end', enforceMinSizeOnResizeEnd);
420
439
 
421
440
  // 监听内容变化相关的事件
422
- window.addEventListener('resize', debouncedMeasureContentHeight);
441
+ window.addEventListener('resize', debouncedMeasureContentSize)
423
442
  });
424
443
 
425
444
  // 监听shape变化,重新计算尺寸
@@ -428,7 +447,7 @@ watch(() => [props.shape.name, props.shape.keywords, props.shape.bounds?.width,
428
447
  nextTick(() => {
429
448
  reportMetrics();
430
449
  // 当内容或宽度变化时重新测量高度
431
- debouncedMeasureContentHeight();
450
+ debouncedMeasureContentSize()
432
451
  });
433
452
  }
434
453
  }, { deep: true }); // 启用深度监听以捕获样式对象的变化
@@ -487,8 +506,7 @@ watch(
487
506
  () => {
488
507
  if (!isResizing.value) {
489
508
  nextTick(() => {
490
- // 重新测量内容高度
491
- debouncedMeasureContentHeight()
509
+ debouncedMeasureContentSize()
492
510
  })
493
511
  }
494
512
  },
@@ -499,7 +517,7 @@ onBeforeUnmount(() => {
499
517
  eventBus.off('shape-drag-end', handleDragEnd);
500
518
  eventBus.off('shape-resize-start', handleDragStart);
501
519
  eventBus.off('shape-resize-end', enforceMinSizeOnResizeEnd);
502
- window.removeEventListener('resize', debouncedMeasureContentHeight);
520
+ window.removeEventListener('resize', debouncedMeasureContentSize)
503
521
  });
504
522
  // ================== 监听 bounds 宽高变化 ==================
505
523
 
@@ -521,24 +539,22 @@ const lastBounds = ref({
521
539
  watch(
522
540
  () => [props.shape.bounds.width, props.shape.bounds.height],
523
541
  ([newW, newH]) => {
524
- if (!isGhost.value) return
525
- // 宽高兜底到默认值(150 x 135)
542
+ // 只有真实图元变化时,才通知父元素扩容
543
+ if (isGhost.value) return
544
+
526
545
  const width = newW ?? DEFAULT_WIDTH
527
546
  const height = newH ?? DEFAULT_HEIGHT
528
547
 
529
- // 如果和上一次一致,直接返回,避免重复触发
530
548
  if (
531
- width == lastBounds.value.width &&
532
- height == lastBounds.value.height
549
+ width === lastBounds.value.width &&
550
+ height === lastBounds.value.height
533
551
  ) {
534
552
  return
535
553
  }
536
554
 
537
- // 更新“上一次”的记录
538
555
  lastBounds.value = { width, height }
539
- // 只有当宽高不再是原始 150 x 135 时才认为“真的变化”,再去调用其他方法
540
- if (
541
- width !== DEFAULT_WIDTH || height !== DEFAULT_HEIGHT) {
556
+
557
+ if (width !== DEFAULT_WIDTH || height !== DEFAULT_HEIGHT) {
542
558
  graphStore.expandParentAndEmitSizeUpdateByChild(props.shape)
543
559
  }
544
560
  }
@@ -909,6 +909,8 @@ function handleCanvasDataChange(data: any[]) {
909
909
  ...d,
910
910
  hasChildren: false,
911
911
  })) as (GanttData & { hasChildren: boolean })[];
912
+ }else{
913
+ ganttItems.value = [];
912
914
  }
913
915
  }
914
916
 
@@ -55,7 +55,8 @@ export const DASHED_EDGE_SHAPES = [
55
55
  'Protects',
56
56
  'MapsToCapability',
57
57
  'ActualResourceRelationship',
58
- 'ProjectSequence'
58
+ 'ProjectSequence',
59
+ 'Supports'
59
60
  ];
60
61
 
61
62
  /**
@@ -92,7 +93,8 @@ export const EDGES_WITH_KEYWORDS = [
92
93
  'Protects',
93
94
  'MapsToCapability',
94
95
  'ActualResourceRelationship',
95
- 'ProjectSequence'
96
+ 'ProjectSequence',
97
+ 'Supports'
96
98
  ];
97
99
 
98
100
  /**
@@ -74,6 +74,7 @@ export const EdgeKeyMap = {
74
74
  'ResourceConnector': 'Edge',//资源连接器
75
75
  'CompetenceToConduct': 'Edge',//开展工作能力
76
76
  'ResponsibleFor': 'Edge',//负责
77
+ 'Supports': 'Edge',//支持
77
78
  } as const
78
79
 
79
80
  // Diagram 类型 (shapeType: 'diagram') - 用于组件渲染映射
@@ -169,11 +170,9 @@ export const DiagramKeyMap = {
169
170
  'ProjectsProcessesDiagram': 'StrategicTaxonomyDiagram', //项目流程图
170
171
  'ProjectsProcessesFlowDiagram': 'StrategicTaxonomyDiagram', //项目内部流程图
171
172
  'ActualProjectMilestoneSummaryTable': 'StrategicTaxonomyDiagram', //实际项目里程碑摘要表
172
- 'ActualProjectsToCapabilitiesMappingMatrix': 'StrategicTaxonomyDiagram', //实际项目与能力映射矩阵
173
173
  'ActualResponsibleResourcesToActualProjectsMappingMatrix': 'StrategicTaxonomyDiagram', //实际负责资源与实际项目映射矩阵
174
174
  'ProjectActivitiesToCapabilitiesMappingMatrix': 'StrategicTaxonomyDiagram', //项目活动到能力映射矩阵
175
175
  'StandardsTaxonomyDiagram': 'StrategicTaxonomyDiagram', //标准概念图
176
- 'StandardsTaxonomyTable': 'StrategicTaxonomyDiagram', //标准概念表
177
176
  'StandardsStructureDiagram': 'StrategicTaxonomyDiagram', //标准结构图
178
177
  'StandardsTraceabilityDiagram': 'StrategicTaxonomyDiagram', //标准可追溯图
179
178
  'ActualResourcesTaxonomyMatrix': 'StrategicTaxonomyDiagram', //实际资源概念矩阵
@@ -231,6 +230,7 @@ export const GanttKeyMap = {
231
230
  'SV8SystemsEvolutionDescriptionDiagram': 'Gantt', //SV-8 系统演进描述甘特图
232
231
  'PV2ProjectTimelinesChart': 'Gantt', //PV-2项目时间进度甘特图
233
232
  } as const
233
+
234
234
  //Table 类型 (shapeType: 'table') - 表格组件渲染映射
235
235
  export const TableKeyMap = {
236
236
  'StrategicTaxonomyTable': 'Table', //战略概念表
@@ -244,15 +244,18 @@ export const TableKeyMap = {
244
244
  'ProjectsTaxonomyTable': 'Table', //项目概念表
245
245
  'ActualProjectMilestoneSummaryTable': 'Table', //实际项目里程碑汇总表
246
246
  'StandardsTraceabilityTable': 'Table', //标准追溯表
247
+ 'ResourcesConnectivityTable': 'Table', //资源连通表
248
+ 'StandardsTaxonomyTable': 'Table', //标准概念表
247
249
 
248
250
  // dodaf
249
251
  'AV2IntegratedDictionaryTable': 'Table', //AV-2集成字典表
250
252
  'SvcV9ServicesTechnologyandSkillsForecastTable': 'Table', //SvcV-9 服务技术与技能预测表
251
253
  'StdV1StandardsProfileTable': 'Table', //StdV-1 标准配置表
252
254
  'StdV2StandardsForecastTable': 'Table', //StdV-2 标准预测表
253
- 'SV9SystemsTechologyandSkillsForecastTable': 'Table', //SV-9 系统技术与技能预测表
255
+ 'SV9SystemsTechologyAndSkillsForecastTable': 'Table', //SV-9 系统技术与技能预测表
254
256
  'SV10aSystemsRulesModelTable': 'Table', //SV-10a 系统规则模型表
255
257
  } as const
258
+
256
259
  //Matrix 类型 (shapeType: 'matrix') - 矩阵组件渲染映射
257
260
  export const MatrixKeyMap = {
258
261
  'StrategicConnectivityMatrix': 'Matrix', //战略概念矩阵
@@ -266,7 +269,8 @@ export const MatrixKeyMap = {
266
269
  'RisksToAssetsMappingMatrix': 'Matrix', //风险到资产映射矩阵
267
270
  'SecurityControlsToRisksMappingMatrix': 'Matrix', //安全控制到风险映射矩阵
268
271
  'ProjectActivitiesToCapabilitiesMappingMatrix': 'Matrix', //项目活动到能力映射矩阵
269
-
272
+ 'ActualProjectsToCapabilitiesMappingMatrix': 'Matrix', //实际项目与能力的映射矩阵
273
+ 'ActualStrategicPhasesToCapabilitiesMappingMatrix': 'Matrix', //实际战略阶段与能力映射矩阵
270
274
  // dodaf
271
275
  'CV5CapabilityToOrganizationDeploymentMapping': 'Matrix', //CV-5能力到组织的映射矩阵
272
276
  'CV6CapabilityToOperationalActivitiesMappingMatrix': 'Matrix', //CV-6能力到业务活动映射矩阵
@@ -280,7 +284,7 @@ export const MatrixKeyMap = {
280
284
  'SvcV6ServicesResourceFlowMatrix': 'Matrix', //SvcV-6 服务资源流矩阵
281
285
  'SvcV7ServicesTypicalMeasuresMatrix': 'Matrix', //SvcV-7 服务典型度量矩阵
282
286
  'SV3SystemsSystemsMatrix': 'Matrix', //SV-3 系统 - 系统矩阵
283
- 'SV5aOperationalActivityToSystemsFunctionTraceabilityMatrix': 'Matrix', //SV-5a 业务活动到系统功能的可追溯性矩阵
287
+ 'SV5aOperationalActivityToSystemsFunctionMatrix': 'Matrix', //SV-5a 业务活动到系统功能的可追溯性矩阵
284
288
  'SV5bOperationalActivityToSystemsTarceabilityMatrix': 'Matrix', //SV-5b 业务活动到系统的可追溯性矩阵
285
289
  'SV6SystemsResourceFlowMatrix': 'Matrix', //SV-6 系统资源流动矩阵
286
290
  'SV7SystemsActualMeasuresMatrix': 'Matrix', //SV-7 系统实际度量矩阵
@@ -504,6 +508,10 @@ export const ShapeKeyMap = {
504
508
  'ResourceParameter': 'Block', //资源参数
505
509
  'ResourceRole': 'Block', //资源角色
506
510
  'ResourceSignal': 'Block', //资源信号
511
+ 'Standard': 'Block', //标准
512
+ 'Protocol': 'Block', //协议
513
+ 'ProtocolStack': 'Block', //协议栈
514
+ 'ProtocolLayer': 'Block', //协议层
507
515
 
508
516
  // DividingLine 类型
509
517
  'EnterpriseGoal': 'DividingLine', //企业目标
@@ -551,7 +559,6 @@ export const ShapeKeyMap = {
551
559
  'StrategicActualStrategicPhaseTaxonomyTable': 'Diagram', //战略实际战略阶段分类表
552
560
  'StrategicActualDeploymentDiagram': 'Diagram', //战略实际部署图
553
561
  'StrategicConnectivityMatrixTable': 'Diagram', //战略连通矩阵表
554
- 'ActualStrategicPhasesToCapabilitiesMappingMatrix': 'Diagram', //实际战略阶段与能力映射矩阵
555
562
  'OperationalConnectivityTable': 'Diagram', //业务连通表
556
563
  'OperationalActivitiesToCapabilitiesMappingMatrix': 'Diagram', //业务活动与能力映射矩阵
557
564
  'OperationalPerformersToCapabilitiesMappingMatrix': 'Diagram', //业务执行者与能力映射矩阵
@@ -587,7 +594,6 @@ export const ShapeKeyMap = {
587
594
  'ResourcesTaxonomyTable': 'Diagram', //资源概念表
588
595
  'ResourcesStructureDiagram': 'Diagram', //资源结构图
589
596
  'ResourcesConnectivityDiagram': 'Diagram', //资源连通图
590
- 'ResourcesConnectivityTable': 'Diagram', //资源连通表
591
597
  'ResourcesInternalConnectivityDiagram': 'Diagram', //资源内部连通图
592
598
  'ResourcesProcessesDiagram': 'Diagram', //资源流程图
593
599
  'ResourcesProcessesFlowDiagram': 'Diagram', //资源内部流程图
@@ -615,17 +621,19 @@ export const ShapeKeyMap = {
615
621
  'ProjectsProcessesDiagram': 'Diagram', //项目流程图
616
622
  'ProjectsProcessesFlowDiagram': 'Diagram', //项目内部流程图
617
623
  'ActualProjectMilestoneSummaryTable': 'Diagram', //实际项目里程碑汇总表
618
- 'ActualProjectsToCapabilitiesMappingMatrix': 'Diagram', //实际项目与能力映射矩阵
619
624
  'ActualResponsibleResourcesToActualProjectsMappingMatrix': 'Diagram', //实际资源与实际项目对应关系矩阵
620
625
  'ProjectActivitiesToCapabilitiesMappingMatrix': 'Diagram', //项目活动与能力映射矩阵
621
626
  'StandardsTaxonomyDiagram': 'Diagram', //标准概念图
622
- 'StandardsTaxonomyTable': 'Diagram', //标准概念表
623
627
  'StandardsStructureDiagram': 'Diagram', //标准结构图
624
628
  'StandardsTraceabilityDiagram': 'Diagram', //标准追溯图
625
629
  'ActualResourcesTaxonomyMatrix': 'Diagram', //实际资源概念矩阵
626
630
  'ActualResourcesStructureDiagram': 'Diagram', //实际资源结构图
627
631
  'ActualResourcesConnectivityDiagram': 'Diagram', //实际资源连通图
628
632
  'ActualStrategicPhasesGanttChart': 'Diagram', //实际战略阶段甘特图
633
+ 'OperationalTaxonomyTable': 'Diagram', //业务概念表
634
+ 'StandardsTaxonomyTable': 'Diagram', //标准概念表
635
+ 'ServicesTaxonomyTable': 'Diagram', //服务概念表
636
+ 'StandardsRoadmapTable': 'Diagram', //标准路线图
629
637
 
630
638
  // DODAF Diagram 类型
631
639
  'AV1OverviewAndSummaryInformationDiagram': 'Diagram', //AV-1概述摘要图
@@ -682,7 +690,7 @@ export const ShapeKeyMap = {
682
690
  'StdV1StandardsProfileTable': 'Diagram', //StdV-1 标准配置表
683
691
  'StdV2StandardsForecastTable': 'Diagram', //StdV-2 标准预测表
684
692
  'SV3SystemsSystemsMatrix': 'Diagram', //SV-3 系统 - 系统矩阵
685
- 'SV5aOperationalActivityToSystemsFunctionTraceabilityMatrix': 'Diagram', //SV-5a 业务活动到系统功能的可追溯性矩阵
693
+ 'SV5aOperationalActivityToSystemsFunctionMatrix': 'Diagram', //SV-5a 业务活动到系统功能的可追溯性矩阵
686
694
  'SV5bOperationalActivityToSystemsTarceabilityMatrix': 'Diagram', //SV-5b 业务活动到系统的可追溯性矩阵
687
695
  'SV6SystemsResourceFlowMatrix': 'Diagram', //SV-6 系统资源流动矩阵
688
696
  'SV7SystemsActualMeasuresMatrix': 'Diagram', //SV-7 系统实际度量矩阵
@@ -21,6 +21,10 @@ interface RemoveContext {
21
21
  selectedIndices: number[]
22
22
  }
23
23
 
24
+ interface AddSuccessContext {
25
+ modelId?: string | null
26
+ }
27
+
24
28
  /**
25
29
  * 行选择 Hook 配置项
26
30
  */
@@ -82,6 +86,7 @@ export function useChartRowSelection<T extends ChartRowItem>({
82
86
  const showContextMenu = ref(false)
83
87
  const contextMenuPosition = ref({ x: 0, y: 0 })
84
88
  const contextMenuTargetItem = ref<T | null>(null)
89
+ const pendingAddSelection = ref<AddSuccessContext | null>(null)
85
90
 
86
91
  /**
87
92
  * 缓存本次“移除”的上下文
@@ -393,19 +398,45 @@ export function useChartRowSelection<T extends ChartRowItem>({
393
398
  * 选中最后一行
394
399
  * 用于新增成功后的默认回选
395
400
  */
396
- function selectLastRow() {
401
+ function selectLastRow(payload?: AddSuccessContext | string) {
397
402
  const list = items.value
398
403
  if (!list.length) {
399
- selectedRowIds.value = new Set()
400
- lastSelectedId.value = null
404
+ pendingAddSelection.value =
405
+ typeof payload === 'string' ? { modelId: payload } : payload ?? null
401
406
  return
402
407
  }
403
408
 
404
- const last = list[list.length - 1]
405
- selectedRowIds.value = new Set([last.id])
406
- lastSelectedId.value = last.id
409
+ const targetModelId =
410
+ typeof payload === 'string'
411
+ ? payload
412
+ : payload?.modelId || null
413
+
414
+ const targetItem = targetModelId
415
+ ? list.find(item => item.modelId === targetModelId)
416
+ : null
417
+
418
+ if (targetModelId && !targetItem) {
419
+ pendingAddSelection.value =
420
+ typeof payload === 'string' ? { modelId: payload } : payload ?? null
421
+ return
422
+ }
423
+
424
+ pendingAddSelection.value = null
425
+ const nextSelected = targetItem || list[list.length - 1]
426
+ selectedRowIds.value = new Set([nextSelected.id])
427
+ lastSelectedId.value = nextSelected.id
428
+ // 默认选中新建行时,同步触发行点击链路,确保属性面板也刷新到当前行。
429
+ eventBus.emit('chart-row-click', nextSelected)
407
430
  }
408
431
 
432
+ watch(
433
+ () => items.value.map(item => `${item.id}:${item.modelId}`).join('|'),
434
+ () => {
435
+ if (!pendingAddSelection.value) return
436
+ selectLastRow(pendingAddSelection.value)
437
+ }
438
+ )
439
+
409
440
  /**
410
441
  * 同步“单行选中”状态
411
442
  * 供属性面板等只关心单选对象的模块使用
@@ -3,6 +3,7 @@ import { eventBus } from '../store';
3
3
  import _ from 'lodash';
4
4
  import { guardOperate } from './license-guard';
5
5
  import { ContextMenuUtils } from './contextMenuUtils';
6
+ import { adjustCanvasToFitAllShapes } from './diagram';
6
7
 
7
8
  // 定义快捷键处理函数类型
8
9
  type KeyboardEventHandler = (e: KeyboardEvent) => void;
@@ -303,6 +304,7 @@ export const createKeyboardHandler = (config: KeyboardConfig): KeyboardEventHand
303
304
  const selectedShapes = graphStore.selectedIds
304
305
  .map(id => graphStore.shapeMap.get(id))
305
306
  .filter((shape): shape is NonNullable<typeof shape> => shape != null);
307
+ const hasNestedSelection = selectedShapes.some(shape => Boolean(shape.parenShapeId));
306
308
 
307
309
  // ==================== 防抖机制:记录初始状态 ====================
308
310
  // 在第一次移动时记录初始bounds
@@ -407,6 +409,17 @@ export const createKeyboardHandler = (config: KeyboardConfig): KeyboardEventHand
407
409
 
408
410
  // ==================== 防抖机制:重置定时器 ====================
409
411
  // 清除之前的定时器
412
+ // 键盘移动嵌套图元后,也要同步扩展父图元,保持与鼠标拖拽行为一致。
413
+ if (hasNestedSelection) {
414
+ selectedShapes.forEach(shape => {
415
+ const currentShape = graphStore.shapeMap.get(shape.id);
416
+ if (currentShape?.parenShapeId) {
417
+ graphStore.expandParentAndEmitSizeUpdateByChild(currentShape);
418
+ }
419
+ });
420
+ adjustCanvasToFitAllShapes();
421
+ }
422
+
410
423
  if (keyboardMoveTimer !== null) {
411
424
  window.clearTimeout(keyboardMoveTimer);
412
425
  }