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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/dist/index.d.ts +362 -2
  2. package/dist/index.esm.js +1090 -688
  3. package/dist/index.esm.js.map +1 -1
  4. package/dist/index.umd.js +1 -1
  5. package/dist/index.umd.js.map +1 -1
  6. package/dist/style.css +1 -1
  7. package/package.json +1 -1
  8. package/src/components/Matrix/Matrix.vue +45 -65
  9. package/src/components/Table/Table.vue +849 -626
  10. package/src/constants/index.ts +23 -9
  11. package/src/statics/icons/childIcons/AV-1/346/246/202/350/277/260/344/270/216/346/221/230/350/246/201/344/277/241/346/201/257/345/214/205@3x.png +0 -0
  12. package/src/statics/icons/childIcons/AV-1/346/246/202/350/277/260/346/221/230/350/246/201/345/233/276@3x.png +0 -0
  13. package/src/statics/icons/childIcons/AV-2/351/233/206/346/210/220/345/255/227/345/205/270/345/214/205@3x.png +0 -0
  14. package/src/statics/icons/childIcons/AV-2/351/233/206/346/210/220/345/255/227/345/205/270/350/241/250@3x.png +0 -0
  15. package/src/statics/icons/childIcons/CV-1/346/204/277/346/231/257/345/214/205@3x.png +0 -0
  16. package/src/statics/icons/childIcons/CV-1/346/204/277/346/231/257/345/233/276@3x.png +0 -0
  17. package/src/statics/icons/childIcons/CV-2/350/203/275/345/212/233/345/210/206/347/261/273/345/214/205@3x.png +0 -0
  18. package/src/statics/icons/childIcons/CV-2/350/203/275/345/212/233/345/210/206/347/261/273/345/233/276@3x-2.png +0 -0
  19. package/src/statics/icons/childIcons/CV-2/350/203/275/345/212/233/345/210/206/347/261/273/345/233/276@3x-3.png +0 -0
  20. package/src/statics/icons/childIcons/CV-2/350/203/275/345/212/233/345/210/206/347/261/273/345/233/276@3x.png +0 -0
  21. package/src/statics/icons/childIcons/CV-3/350/203/275/345/212/233/345/210/206/346/256/265/345/214/205@3x.png +0 -0
  22. package/src/statics/icons/childIcons/CV-3/350/203/275/345/212/233/351/230/266/346/256/265/347/224/230/347/211/271/345/233/276@3x.png +0 -0
  23. package/src/statics/icons/childIcons/CV-4/350/203/275/345/212/233/344/276/235/350/265/226/345/214/205@3x.png +0 -0
  24. package/src/statics/icons/childIcons/CV-4/350/203/275/345/212/233/344/276/235/350/265/226/345/233/276@3x.png +0 -0
  25. package/src/statics/icons/childIcons/CV-5/350/203/275/345/212/233/345/210/260/347/273/204/347/273/207/347/232/204/345/274/200/345/217/221/346/230/240/345/260/204/345/214/205@3x.png +0 -0
  26. package/src/statics/icons/childIcons/CV-5/350/203/275/345/212/233/345/210/260/347/273/204/347/273/207/347/232/204/346/230/240/345/260/204/347/237/251/351/230/265@3x.png +0 -0
  27. package/src/statics/icons/childIcons/CV-6/350/203/275/345/212/233/345/210/260/344/270/232/345/212/241/346/264/273/345/212/250/346/230/240/345/260/204/347/237/251/351/230/265@3x.png +0 -0
  28. package/src/statics/icons/childIcons/CV-6/350/203/275/345/212/233/345/210/260/344/275/234/346/210/230/346/264/273/345/212/250/347/232/204/346/230/240/345/260/204/345/214/205@3x.png +0 -0
  29. package/src/statics/icons/childIcons/CV-7/350/203/275/345/212/233/345/210/260/346/234/215/345/212/241/346/230/240/345/260/204/347/237/251/351/230/265@3x.png +0 -0
  30. package/src/statics/icons/childIcons/CV-7/350/203/275/345/212/233/345/210/260/346/234/215/345/212/241/347/232/204/346/230/240/345/260/204/345/214/205@3x.png +0 -0
  31. package/src/statics/icons/childIcons/DIV-1/346/246/202/345/277/265/346/225/260/346/215/256/346/250/241/345/236/213/345/214/205@3x.png +0 -0
  32. package/src/statics/icons/childIcons/DIV-1/346/246/202/345/277/265/346/225/260/346/215/256/346/250/241/345/236/213/345/233/276@3x.png +0 -0
  33. package/src/statics/icons/childIcons/DIV-2/351/200/273/350/276/221/346/225/260/346/215/256/346/250/241/345/236/213/345/214/205@3x.png +0 -0
  34. package/src/statics/icons/childIcons/DIV-2/351/200/273/350/276/221/346/225/260/346/215/256/346/250/241/345/236/213/345/233/276@3x.png +0 -0
  35. 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/214/205@3x.png +0 -0
  36. package/src/statics/icons/childIcons/OV-1/350/207/252/347/224/261/345/210/206/347/261/273/345/233/276@3x.png +0 -0
  37. package/src/statics/icons/childIcons/OV-1/351/253/230/347/272/247/344/275/234/346/210/230/346/246/202/345/277/265/345/233/276@3x.png +0 -0
  38. package/src/statics/icons/childIcons/OV-1/351/253/230/347/272/247/344/275/234/346/210/230/346/246/202/345/277/265/345/233/276/345/214/205@3x.png +0 -0
  39. package/src/statics/icons/childIcons/OV-2/344/275/234/346/210/230/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-2.png +0 -0
  40. package/src/statics/icons/childIcons/OV-2/344/275/234/346/210/230/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
  41. package/src/statics/icons/childIcons/OV-2/344/275/234/346/210/230/350/265/204/346/272/220/346/265/201/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  42. package/src/statics/icons/childIcons/OV-2/344/275/234/346/210/230/350/265/204/346/272/220/346/265/201/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  43. package/src/statics/icons/childIcons/OV-3/344/275/234/346/210/230/350/265/204/346/272/220/346/265/201/347/237/251/351/230/265@3x.png +0 -0
  44. package/src/statics/icons/childIcons/OV-3/344/275/234/346/210/230/350/265/204/346/272/220/346/265/201/347/237/251/351/230/265/345/214/205@3x.png +0 -0
  45. package/src/statics/icons/childIcons/OV-3/345/237/272/347/241/200/350/247/222/350/211/262/344/275/234/346/210/230/350/265/204/346/272/220/346/265/201/347/237/251/351/230/265@3x.png +0 -0
  46. package/src/statics/icons/childIcons/OV-4/347/273/204/347/273/207/345/205/263/347/263/273/345/233/276@3x.png +0 -0
  47. package/src/statics/icons/childIcons/OV-4/347/273/204/347/273/207/345/205/263/347/263/273/345/233/276/345/214/205@3x.png +0 -0
  48. package/src/statics/icons/childIcons/OV-5a/344/275/234/346/210/230/346/264/273/345/212/250/345/210/206/350/247/243/346/240/221/345/214/205@3x.png +0 -0
  49. package/src/statics/icons/childIcons/OV-5a/344/275/234/346/210/230/346/264/273/345/212/250/345/210/206/350/247/243/346/240/221/345/233/276@3x.png +0 -0
  50. package/src/statics/icons/childIcons/OV-5b/344/275/234/346/210/230/346/264/273/345/212/250/346/250/241/345/236/213/345/214/205@3x.png +0 -0
  51. package/src/statics/icons/childIcons/OV-5b/344/275/234/346/210/230/346/264/273/345/212/250/346/250/241/345/236/213/345/233/276@3x.png +0 -0
  52. package/src/statics/icons/childIcons/OV-6a/344/275/234/346/210/230/350/247/204/345/210/231/346/250/241/345/236/213/345/214/205@3x.png +0 -0
  53. package/src/statics/icons/childIcons/OV-6a/344/275/234/346/210/230/350/265/204/346/272/220/345/217/202/346/225/260/345/233/276@3x.png +0 -0
  54. package/src/statics/icons/childIcons/OV-6b/347/212/266/346/200/201/350/275/254/346/215/242/345/233/276@3x.png +0 -0
  55. package/src/statics/icons/childIcons/OV-6b/347/212/266/346/200/201/350/275/254/346/215/242/346/250/241/345/236/213/345/214/205@3x.png +0 -0
  56. package/src/statics/icons/childIcons/OV-6c/344/272/213/344/273/266/350/277/275/350/270/252/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  57. package/src/statics/icons/childIcons/OV-6c/344/275/234/346/210/230/344/272/213/344/273/266/350/267/237/350/270/252/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  58. package/src/statics/icons/childIcons/PV-1/351/241/271/347/233/256/347/273/204/345/220/210/345/205/263/347/263/273/345/214/205@3x.png +0 -0
  59. package/src/statics/icons/childIcons/PV-1/351/241/271/347/233/256/347/273/204/345/220/210/345/205/263/347/263/273/345/233/276@3x.png +0 -0
  60. package/src/statics/icons/childIcons/PV-2/351/241/271/347/233/256/346/227/266/351/227/264/350/277/233/345/272/246/345/214/205@3x.png +0 -0
  61. package/src/statics/icons/childIcons/PV-2/351/241/271/347/233/256/346/227/266/351/227/264/350/277/233/345/272/246/347/224/230/347/211/271/345/233/276@3x.png +0 -0
  62. package/src/statics/icons/childIcons/PV-3/351/241/271/347/233/256/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
  63. package/src/statics/icons/childIcons/PV-3/351/241/271/347/233/256/344/270/216/350/203/275/345/212/233/347/232/204/346/230/240/345/260/204/345/214/205@3x.png +0 -0
  64. package/src/statics/icons/childIcons/SV-1 /347/263/273/347/273/237/346/216/245/345/217/243/345/206/205/351/203/250/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  65. package/src/statics/icons/childIcons/SV-1 /347/263/273/347/273/237/346/216/245/345/217/243/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  66. package/src/statics/icons/childIcons/SV-10a /347/263/273/347/273/237/345/217/202/346/225/260/345/233/276@3x.png +0 -0
  67. package/src/statics/icons/childIcons/SV-10a /347/263/273/347/273/237/350/247/204/345/210/231/346/250/241/345/236/213/350/241/250@3x.png +0 -0
  68. package/src/statics/icons/childIcons/SV-10a/347/263/273/347/273/237/350/247/204/345/210/231/346/250/241/345/236/213/345/214/205@3x.png +0 -0
  69. package/src/statics/icons/childIcons/SV-10b /347/263/273/347/273/237/347/212/266/346/200/201/350/275/254/346/215/242/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  70. package/src/statics/icons/childIcons/SV-10b/347/263/273/347/273/237/347/212/266/346/200/201/350/275/254/346/215/242/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  71. package/src/statics/icons/childIcons/SV-10c /347/263/273/347/273/237/344/272/213/344/273/266/350/267/237/350/270/252/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  72. package/src/statics/icons/childIcons/SV-10c/347/263/273/347/273/237/344/272/213/344/273/266-/350/277/275/350/270/252/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  73. package/src/statics/icons/childIcons/SV-1/347/263/273/347/273/237/346/216/245/345/217/243/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  74. package/src/statics/icons/childIcons/SV-2 /347/263/273/347/273/237/345/206/205/351/203/250/350/265/204/346/272/220/346/265/201/345/212/250/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  75. package/src/statics/icons/childIcons/SV-2 /347/263/273/347/273/237/350/265/204/346/272/220/346/265/201/345/212/250/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  76. package/src/statics/icons/childIcons/SV-2/347/263/273/347/273/237/350/265/204/346/272/220/346/265/201/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  77. 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@3x.png +0 -0
  78. 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/345/214/205@3x.png +0 -0
  79. package/src/statics/icons/childIcons/SV-4 /347/263/273/347/273/237/345/212/237/350/203/275/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  80. package/src/statics/icons/childIcons/SV-4 /347/263/273/347/273/237/345/212/237/350/203/275/346/265/201/347/250/213/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  81. package/src/statics/icons/childIcons/SV-4/347/263/273/347/273/237/345/212/237/350/203/275/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  82. package/src/statics/icons/childIcons/SV-5a /344/270/232/345/212/241/346/264/273/345/212/250/345/210/260/347/263/273/347/273/237/345/212/237/350/203/275/347/232/204/345/217/257/350/277/275/346/272/257/346/200/247/347/237/251/351/230/265@3x.png +0 -0
  83. package/src/statics/icons/childIcons/SV-5a/344/275/234/346/210/230/346/264/273/345/212/250/345/210/260/347/263/273/347/273/237/345/212/237/350/203/275/345/217/257/350/277/275/350/270/252/347/237/251/351/230/265/345/214/205@3x.png +0 -0
  84. package/src/statics/icons/childIcons/SV-5b /344/270/232/345/212/241/346/264/273/345/212/250/345/210/260/347/263/273/347/273/237/347/232/204/345/217/257/350/277/275/346/272/257/346/200/247/347/237/251/351/230/265@3x.png +0 -0
  85. package/src/statics/icons/childIcons/SV-5b/344/275/234/346/210/230/346/264/273/345/212/250/345/210/260/347/263/273/347/273/237/345/217/257/350/277/275/350/270/252/347/237/251/351/230/265/345/214/205@3x.png +0 -0
  86. package/src/statics/icons/childIcons/SV-6 /347/263/273/347/273/237/350/265/204/346/272/220/346/265/201/345/212/250/347/237/251/351/230/265@3x.png +0 -0
  87. package/src/statics/icons/childIcons/SV-6/347/263/273/347/273/237/350/265/204/346/272/220/346/265/201/347/237/251/351/230/265/345/214/205@3x.png +0 -0
  88. package/src/statics/icons/childIcons/SV-7 /347/263/273/347/273/237/345/256/236/351/231/205/345/272/246/351/207/217/347/237/251/351/230/265@3x.png +0 -0
  89. package/src/statics/icons/childIcons/SV-7/347/263/273/347/273/237/345/272/246/351/207/217/347/237/251/351/230/265/345/214/205@3x.png +0 -0
  90. package/src/statics/icons/childIcons/SV-8 /347/263/273/347/273/237/346/274/224/350/277/233/346/217/217/350/277/260/347/224/230/347/211/271/345/233/276@3x.png +0 -0
  91. package/src/statics/icons/childIcons/SV-8/347/263/273/347/273/237/346/274/224/350/277/233/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  92. package/src/statics/icons/childIcons/SV-9 /347/263/273/347/273/237/346/212/200/346/234/257/344/270/216/346/212/200/350/203/275/351/242/204/346/265/213/350/241/250@3x.png +0 -0
  93. package/src/statics/icons/childIcons/SV-9/347/263/273/347/273/237/346/212/200/346/234/257/344/270/216/346/212/200/350/203/275/351/242/204/346/265/213/345/214/205@3x.png +0 -0
  94. package/src/statics/icons/childIcons/StdV-1 /346/240/207/345/207/206/351/205/215/347/275/256/350/241/250@3x.png +0 -0
  95. package/src/statics/icons/childIcons/StdV-1/346/240/207/345/207/206/351/205/215/347/275/256/346/226/207/344/273/266/345/214/205@3x.png +0 -0
  96. package/src/statics/icons/childIcons/StdV-2 /346/240/207/345/207/206/351/242/204/346/265/213/350/241/250@3x.png +0 -0
  97. package/src/statics/icons/childIcons/StdV-2/346/240/207/345/207/206/351/242/204/346/265/213/345/214/205@3x.png +0 -0
  98. package/src/statics/icons/childIcons/SvcV-10a /346/234/215/345/212/241/345/217/202/346/225/260/345/233/276@3x.png +0 -0
  99. package/src/statics/icons/childIcons/SvcV-10a/346/234/215/345/212/241/350/247/204/345/210/231/346/250/241/345/236/213/345/214/205@3x.png +0 -0
  100. package/src/statics/icons/childIcons/SvcV-10b /346/234/215/345/212/241/347/212/266/346/200/201/350/275/254/346/215/242/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  101. package/src/statics/icons/childIcons/SvcV-10b/346/234/215/345/212/241/347/212/266/346/200/201/350/275/254/346/215/242/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  102. package/src/statics/icons/childIcons/SvcV-10c /346/234/215/345/212/241/344/272/213/344/273/266/350/267/237/350/270/252/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  103. package/src/statics/icons/childIcons/SvcV-10c/346/234/215/345/212/241/344/272/213/344/273/266-/350/277/275/350/270/252/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  104. package/src/statics/icons/childIcons/SvcV-1/346/234/215/345/212/241/344/270/212/344/270/213/346/226/207/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  105. package/src/statics/icons/childIcons/SvcV-1/346/234/215/345/212/241/350/203/214/346/231/257/346/250/241/345/236/213/345/214/205@3x.png +0 -0
  106. package/src/statics/icons/childIcons/SvcV-2 /346/234/215/345/212/241/350/265/204/346/272/220/346/265/201/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  107. package/src/statics/icons/childIcons/SvcV-2/346/234/215/345/212/241/350/265/204/346/272/220/346/265/201/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  108. package/src/statics/icons/childIcons/SvcV-3a /347/263/273/347/273/237 -/346/234/215/345/212/241/347/237/251/351/230/265@3x-2.png +0 -0
  109. package/src/statics/icons/childIcons/SvcV-3a /347/263/273/347/273/237 -/346/234/215/345/212/241/347/237/251/351/230/265@3x.png +0 -0
  110. package/src/statics/icons/childIcons/SvcV-3a/347/263/273/347/273/237-/346/234/215/345/212/241/347/237/251/351/230/265/345/214/205@3x.png +0 -0
  111. 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/345/214/205@3x.png +0 -0
  112. package/src/statics/icons/childIcons/SvcV-4 /346/234/215/345/212/241/345/212/237/350/203/275/346/217/217/350/277/260/345/233/276@3x.png +0 -0
  113. package/src/statics/icons/childIcons/SvcV-4 /346/234/215/345/212/241/345/212/237/350/203/275/346/265/201/345/233/276@3x.png +0 -0
  114. package/src/statics/icons/childIcons/SvcV-4/346/234/215/345/212/241/345/212/237/350/203/275/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  115. package/src/statics/icons/childIcons/SvcV-5/344/275/234/346/210/230/346/264/273/345/212/250/345/210/260/346/234/215/345/212/241/345/217/257/350/277/275/350/270/252/347/237/251/351/230/265/345/214/205@3x.png +0 -0
  116. package/src/statics/icons/childIcons/SvcV-6 /346/234/215/345/212/241/350/265/204/346/272/220/346/265/201/347/237/251/351/230/265@3x.png +0 -0
  117. package/src/statics/icons/childIcons/SvcV-6/346/234/215/345/212/241/350/265/204/346/272/220/346/265/201/347/237/251/351/230/265/345/214/205@3x.png +0 -0
  118. package/src/statics/icons/childIcons/SvcV-7 /346/234/215/345/212/241/345/205/270/345/236/213/345/272/246/351/207/217/347/237/251/351/230/265@3x.png +0 -0
  119. package/src/statics/icons/childIcons/SvcV-7/346/234/215/345/212/241/345/272/246/351/207/217/347/237/251/351/230/265/345/214/205@3x.png +0 -0
  120. package/src/statics/icons/childIcons/SvcV-8 /346/234/215/345/212/241/346/274/224/350/277/233/347/224/230/347/211/271/345/233/276@3x.png +0 -0
  121. package/src/statics/icons/childIcons/SvcV-8/346/234/215/345/212/241/346/274/224/350/277/233/346/217/217/350/277/260/345/214/205@3x.png +0 -0
  122. package/src/statics/icons/childIcons/SvcV-9 /346/234/215/345/212/241/346/212/200/346/234/257/344/270/216/346/212/200/350/203/275/351/242/204/346/265/213/350/241/250@3x.png +0 -0
  123. package/src/statics/icons/childIcons/SvcV-9/346/234/215/345/212/241/346/212/200/346/234/257/344/270/216/346/212/200/350/203/275/351/242/204/346/265/213/345/214/205@3x.png +0 -0
  124. package/src/statics/icons/childIcons//344/275/223/347/263/273/346/236/266/346/236/204@3x.png +0 -0
  125. package/src/statics/icons/childIcons//344/275/234/346/210/230/350/247/206/350/247/222@3x.png +0 -0
  126. package/src/statics/icons/childIcons//345/205/250/346/231/257/350/247/206/350/247/222@3x.png +0 -0
  127. package/src/statics/icons/childIcons//345/205/254/345/217/270@3x.png +0 -0
  128. package/src/statics/icons/childIcons//345/215/217/350/256/256@3x.png +0 -0
  129. package/src/statics/icons/childIcons//345/215/217/350/256/256/345/261/202@3x.png +0 -0
  130. package/src/statics/icons/childIcons//345/215/217/350/256/256/346/240/210@3x.png +0 -0
  131. package/src/statics/icons/childIcons//346/224/257/346/214/201@3x.png +0 -0
  132. package/src/statics/icons/childIcons//346/225/260/346/215/256/344/277/241/346/201/257/350/247/206/350/247/222@3x.png +0 -0
  133. package/src/statics/icons/childIcons//346/234/215/345/212/241/350/247/206/350/247/222@3x.png +0 -0
  134. package/src/statics/icons/childIcons//346/240/207/345/207/206@3x.png +0 -0
  135. package/src/statics/icons/childIcons//346/240/207/345/207/206/350/247/206/350/247/222@3x.png +0 -0
  136. package/src/statics/icons/childIcons//347/263/273/347/273/237/350/247/206/350/247/222@3x.png +0 -0
  137. package/src/statics/icons/childIcons//350/203/275/345/212/233/350/247/206/350/247/222@3x.png +0 -0
  138. package/src/statics/icons/childIcons//351/241/271/347/233/256/350/247/206/350/247/222@3x.png +0 -0
  139. package/src/store/graphStore.ts +21 -1
  140. package/src/types/index.ts +1 -0
@@ -1,216 +1,305 @@
1
1
  <template>
2
- <div class="gantt-container" @click="onContainerClick">
3
- <!-- 左侧表格 -->
4
- <div class="gantt-left" :class="{ 'with-search-bar': showSearchBar }" ref="tableContainerRef" @scroll="() => syncVirtualViewportState()">
5
- <table class="gantt-table" :style="{ width: tableWidth + 'px' }">
6
- <!-- colgroup 统一控制整列宽度 -->
7
- <colgroup>
8
- <col v-for="col in displayColumns" :key="col.configId"
9
- :style="{ width: getColumnWidth(col.configId) + 'px', }" />
10
- </colgroup>
11
- <thead>
12
- <tr class="header-row-2">
13
- <th v-for="col in displayColumns" :key="col.id" class="col-date">
14
- <div class="th-content">
15
- <div v-if="col.configId == 'index'" style="text-align: center;">{{ col.name }}</div>
16
- <div v-else class="th-label">{{ col.name }}</div>
17
- <div v-if="col.configId !== 'index'" class="col-resizer"
18
- @mousedown="startColumnResize(col.configId, $event)"></div>
19
- </div>
20
- </th>
21
- </tr>
22
- </thead>
23
-
24
- <tbody>
25
- <!-- 上方占位空间 -->
26
- <tr v-if="virtualTopSpacerHeight > 0" class="table-spacer-row" aria-hidden="true">
27
- <td :colspan="visibleColumnSpan">
28
- <div class="table-spacer" :style="{ height: virtualTopSpacerHeight + 'px' }"></div>
29
- </td>
30
- </tr>
31
-
32
- <!-- 虚拟行 -->
33
- <tr v-for="row in virtualRows" :key="row.item.id" class="gantt-row"
34
- :class="{ 'row-selected': selectedRowIds.has(row.item.id) }"
35
- @click.stop="selectRow(row.item.id, $event)" @contextmenu="handleContextMenu(row.item, $event)">
36
- <td v-for="col in displayColumns" :key="col.configId" class="col-date"
37
- :title="getDisplayCellValue(row.item, col)"
38
- @dblclick.stop="col.configId !== 'index' && openCellEditor(row.item, col)">
39
- <!-- 编辑态:根据列的 valueType 渲染不同编辑控件(Element Plus) -->
40
- <template v-if="isCellEditing(row.item.id, col.configId)">
41
- <!-- 布尔:开关 -->
42
- <el-switch
43
- v-if="editingTextCell?.editorType === 'Boolean'"
44
- v-model="editingTextCell!.value"
45
- size="small"
46
- class="cell-switch"
47
- @click.stop
48
- @change="saveTextEdit(row.item, col.configId)"
49
- />
50
- <!-- 日期:日期时间选择器 -->
51
- <el-date-picker
52
- v-else-if="editingTextCell?.editorType === 'Date'"
53
- :ref="setEditingInputRef"
54
- v-model="editingTextCell!.value"
55
- type="datetime"
56
- size="small"
57
- class="cell-date"
58
- format="YYYY-MM-DD HH:mm:ss"
59
- value-format="YYYY-MM-DD HH:mm:ss"
60
- :teleported="false"
61
- :clearable="true"
62
- :editable="false"
63
- @click.stop
64
- @change="saveTextEdit(row.item, col.configId)"
65
- @blur="saveTextEdit(row.item, col.configId)"
66
- @keydown.esc.prevent="closeCellEditor"
67
- />
68
- <!-- 枚举:下拉选择,选项来自后端 literals -->
69
- <el-select
70
- v-else-if="editingTextCell?.editorType === 'Enumeration' && col.literals && col.literals.length"
71
- v-model="editingTextCell!.value"
72
- size="small"
73
- class="cell-select"
74
- @click.stop
75
- @change="saveTextEdit(row.item, col.configId)"
76
- @blur="saveTextEdit(row.item, col.configId)"
77
- >
78
- <el-option
79
- v-for="opt in col.literals"
80
- :key="opt.value"
81
- :label="opt.key"
82
- :value="opt.value"
83
- />
84
- </el-select>
85
- <!-- 富文本:先用 textarea(属性面板是弹窗富文本,这里做轻量版) -->
86
- <el-input
87
- v-else-if="editingTextCell?.editorType === 'Html'"
88
- :ref="setEditingInputRef"
89
- v-model="editingTextCell!.value"
90
- type="textarea"
91
- autosize
92
- size="small"
93
- class="cell-textarea"
94
- @click.stop
95
- @blur="saveTextEdit(row.item, col.configId)"
96
- @keydown.esc.prevent="closeCellEditor"
97
- />
98
- <!-- 其他(String、Integer 等):文本/数字输入框 -->
99
- <el-input
100
- v-else
101
- :ref="setEditingInputRef"
102
- v-model="editingTextCell!.value"
103
- :type="editingTextCell?.editorType === 'Integer' ? 'number' : 'text'"
104
- size="small"
105
- class="cell-input"
106
- @click.stop
107
- @blur="saveTextEdit(row.item, col.configId)"
108
- @keydown.enter.prevent="saveTextEdit(row.item, col.configId)"
109
- @keydown.esc.prevent="closeCellEditor"
110
- />
111
- </template>
112
-
113
- <!-- 显示态 -->
114
- <template v-else>
115
- <div v-if="col.configId === 'index'" class="item-index" style="text-align: center;">
116
- {{ row.index + 1 }}
117
- </div>
118
- <div v-else class="item-name">
119
- <div v-if="getDisplayCellIcon(row.item, col)" class="expand-icon">
120
- <img :src="getIcon('childIcons', getDisplayCellIcon(row.item, col))" alt=""
121
- style="width: 16px; height: 16px; display: block;" />
122
- </div>
123
- <span class="cell-text">{{ getDisplayCellValue(row.item, col) }}</span>
124
- </div>
125
- </template>
126
- </td>
127
- </tr>
128
-
129
- <!-- 下方占位空间 -->
130
- <tr v-if="virtualBottomSpacerHeight > 0" class="table-spacer-row" aria-hidden="true">
131
- <td :colspan="visibleColumnSpan">
132
- <div class="table-spacer" :style="{ height: virtualBottomSpacerHeight + 'px' }"></div>
133
- </td>
134
- </tr>
135
- </tbody>
136
- </table>
137
- </div>
138
- <!-- 右键菜单 -->
139
- <GanttContextMenu v-model:visible="showContextMenu" :position="contextMenuPosition" :can-move-up="canMoveUp"
140
- :can-move-down="canMoveDown" @property-config="handlePropertyConfig" @tree-highlight="handleTreeHighlight"
141
- @move-up="handleMoveUpFromMenu" @move-down="handleMoveDownFromMenu" @delete="handleDeleteFromMenu"
142
- @remove="handleRemoveFromMenu" />
2
+ <div class="gantt-container" @click="onContainerClick">
3
+ <!-- 左侧表格 -->
4
+ <div
5
+ class="gantt-left"
6
+ :class="{ 'with-search-bar': showSearchBar }"
7
+ ref="tableContainerRef"
8
+ @scroll="() => syncVirtualViewportState()"
9
+ >
10
+ <table class="gantt-table" :style="{ width: tableWidth + 'px' }">
11
+ <!-- 用 colgroup 统一控制整列宽度 -->
12
+ <colgroup>
13
+ <col
14
+ v-for="col in displayColumns"
15
+ :key="col.configId"
16
+ :style="{ width: getColumnWidth(col.configId) + 'px' }"
17
+ />
18
+ </colgroup>
19
+ <thead>
20
+ <tr class="header-row-2">
21
+ <th v-for="col in displayColumns" :key="col.id" class="col-date">
22
+ <div class="th-content">
23
+ <div v-if="col.configId == 'index'" style="text-align: center">
24
+ {{ col.name }}
25
+ </div>
26
+ <div v-else class="th-label">{{ col.name }}</div>
27
+ <div
28
+ v-if="col.configId !== 'index'"
29
+ class="col-resizer"
30
+ @mousedown="startColumnResize(col.configId, $event)"
31
+ ></div>
32
+ </div>
33
+ </th>
34
+ </tr>
35
+ </thead>
36
+
37
+ <tbody>
38
+ <!-- 上方占位空间 -->
39
+ <tr
40
+ v-if="virtualTopSpacerHeight > 0"
41
+ class="table-spacer-row"
42
+ aria-hidden="true"
43
+ >
44
+ <td :colspan="visibleColumnSpan">
45
+ <div
46
+ class="table-spacer"
47
+ :style="{ height: virtualTopSpacerHeight + 'px' }"
48
+ ></div>
49
+ </td>
50
+ </tr>
51
+
52
+ <!-- 虚拟行 -->
53
+ <tr
54
+ v-for="row in virtualRows"
55
+ :key="row.item.id"
56
+ class="gantt-row"
57
+ :class="{ 'row-selected': selectedRowIds.has(row.item.id) }"
58
+ @click.stop="selectRow(row.item.id, $event)"
59
+ @contextmenu="handleContextMenu(row.item, $event)"
60
+ >
61
+ <td
62
+ v-for="col in displayColumns"
63
+ :key="col.configId"
64
+ class="col-date"
65
+ :title="getDisplayCellValue(row.item, col)"
66
+ @dblclick.stop="
67
+ col.configId !== 'index' && openCellEditor(row.item, col)
68
+ "
69
+ >
70
+ <!-- 编辑态:根据列的 valueType 渲染不同编辑控件(Element Plus) -->
71
+ <template v-if="isCellEditing(row.item.id, col.configId)">
72
+ <!-- 布尔:单选(与属性面板保持一致) -->
73
+ <el-radio-group
74
+ v-if="editingTextCell?.editorType === 'Boolean'"
75
+ v-model="editingTextCell!.value"
76
+ class="cell-boolean-group"
77
+ @click.stop
78
+ @change="saveTextEdit(row.item, col.configId)"
79
+ >
80
+ <el-radio :label="true" size="small">是</el-radio>
81
+ <el-radio :label="false" size="small">否</el-radio>
82
+ </el-radio-group>
83
+ <!-- 日期:日期时间选择器 -->
84
+ <el-date-picker
85
+ v-else-if="editingTextCell?.editorType === 'Date'"
86
+ :ref="setEditingInputRef"
87
+ v-model="editingTextCell!.value"
88
+ type="datetime"
89
+ size="small"
90
+ class="cell-date"
91
+ format="YYYY-MM-DD HH:mm:ss"
92
+ value-format="YYYY-MM-DD HH:mm:ss"
93
+ :teleported="false"
94
+ :clearable="true"
95
+ :editable="false"
96
+ @click.stop
97
+ @change="saveTextEdit(row.item, col.configId)"
98
+ @blur="saveTextEdit(row.item, col.configId)"
99
+ @keydown.esc.prevent="closeCellEditor"
100
+ />
101
+ <!-- 枚举:下拉选择,选项来自后端 literals -->
102
+ <el-select
103
+ v-else-if="
104
+ editingTextCell?.editorType === 'Enumeration' &&
105
+ col.literals &&
106
+ col.literals.length
107
+ "
108
+ v-model="editingTextCell!.value"
109
+ size="small"
110
+ class="cell-select"
111
+ @click.stop
112
+ @change="saveTextEdit(row.item, col.configId)"
113
+ @blur="saveTextEdit(row.item, col.configId)"
114
+ >
115
+ <el-option
116
+ v-for="opt in col.literals"
117
+ :key="opt.value"
118
+ :label="opt.key"
119
+ :value="opt.value"
120
+ />
121
+ </el-select>
122
+ <!-- 富文本:先用 textarea(属性面板是弹窗富文本,这里做轻量版) -->
123
+ <el-input
124
+ v-else-if="editingTextCell?.editorType === 'Html'"
125
+ :ref="setEditingInputRef"
126
+ v-model="editingTextCell!.value"
127
+ type="textarea"
128
+ autosize
129
+ size="small"
130
+ class="cell-textarea"
131
+ @click.stop
132
+ @blur="saveTextEdit(row.item, col.configId)"
133
+ @keydown.esc.prevent="closeCellEditor"
134
+ />
135
+ <!-- 其他(String、Integer 等):文本/数字输入框 -->
136
+ <el-input
137
+ v-else
138
+ :ref="setEditingInputRef"
139
+ v-model="editingTextCell!.value"
140
+ :type="
141
+ editingTextCell?.editorType === 'Integer'
142
+ ? 'number'
143
+ : 'text'
144
+ "
145
+ size="small"
146
+ class="cell-input"
147
+ @click.stop
148
+ @blur="saveTextEdit(row.item, col.configId)"
149
+ @keydown.enter.prevent="saveTextEdit(row.item, col.configId)"
150
+ @keydown.esc.prevent="closeCellEditor"
151
+ />
152
+ </template>
153
+
154
+ <!-- 显示态 -->
155
+ <template v-else>
156
+ <div
157
+ v-if="col.configId === 'index'"
158
+ class="item-index"
159
+ style="text-align: center"
160
+ >
161
+ {{ row.index + 1 }}
162
+ </div>
163
+ <div
164
+ v-else-if="
165
+ col.valueType === 'Boolean' &&
166
+ hasBooleanCellValue(row.item, col.configId)
167
+ "
168
+ class="item-name cell-boolean-display"
169
+ >
170
+ <el-radio-group
171
+ :model-value="normalizeBooleanValue((row.item as any)[col.configId])"
172
+ class="cell-boolean-group"
173
+ :disabled="col.isReadonly === true"
174
+ @click.stop
175
+ @change="handleBooleanCellChange(row.item, col.configId, $event)"
176
+ >
177
+ <el-radio :label="true" size="small">是</el-radio>
178
+ <el-radio :label="false" size="small">否</el-radio>
179
+ </el-radio-group>
180
+ </div>
181
+ <div v-else-if="col.valueType === 'Boolean'" class="item-name"></div>
182
+ <div v-else class="item-name">
183
+ <div
184
+ v-if="getDisplayCellIcon(row.item, col)"
185
+ class="expand-icon"
186
+ >
187
+ <img
188
+ :src="
189
+ getIcon('childIcons', getDisplayCellIcon(row.item, col))
190
+ "
191
+ alt=""
192
+ style="width: 16px; height: 16px; display: block"
193
+ />
194
+ </div>
195
+ <span class="cell-text">{{
196
+ getDisplayCellValue(row.item, col)
197
+ }}</span>
198
+ </div>
199
+ </template>
200
+ </td>
201
+ </tr>
202
+
203
+ <!-- 下方占位空间 -->
204
+ <tr
205
+ v-if="virtualBottomSpacerHeight > 0"
206
+ class="table-spacer-row"
207
+ aria-hidden="true"
208
+ >
209
+ <td :colspan="visibleColumnSpan">
210
+ <div
211
+ class="table-spacer"
212
+ :style="{ height: virtualBottomSpacerHeight + 'px' }"
213
+ ></div>
214
+ </td>
215
+ </tr>
216
+ </tbody>
217
+ </table>
143
218
  </div>
219
+ <!-- 右键菜单 -->
220
+ <GanttContextMenu
221
+ v-model:visible="showContextMenu"
222
+ :position="contextMenuPosition"
223
+ :can-move-up="canMoveUp"
224
+ :can-move-down="canMoveDown"
225
+ @property-config="handlePropertyConfig"
226
+ @tree-highlight="handleTreeHighlight"
227
+ @move-up="handleMoveUpFromMenu"
228
+ @move-down="handleMoveDownFromMenu"
229
+ @delete="handleDeleteFromMenu"
230
+ @remove="handleRemoveFromMenu"
231
+ />
232
+ </div>
144
233
  </template>
145
234
 
146
235
  <script setup lang="ts">
147
- import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
148
- import type { Shape, GanttData, GanttColumn } from '../../types'
149
- import { eventBus } from '../../store/eventBus'
150
- import GanttContextMenu from '../GanttContextMenu/GanttContextMenu.vue'
151
- import { getIcon } from '../../utils/iconLoader'
152
- import { useChartRowSelection, useVirtualScroll } from '../../hooks'
236
+ import { computed, nextTick, onMounted, onUnmounted, ref, watch } from "vue";
237
+ import type { Shape, GanttData, GanttColumn } from "../../types";
238
+ import { eventBus } from "../../store/eventBus";
239
+ import GanttContextMenu from "../GanttContextMenu/GanttContextMenu.vue";
240
+ import { getIcon } from "../../utils/iconLoader";
241
+ import { useChartRowSelection, useVirtualScroll } from "../../hooks";
153
242
  /**
154
243
  * 组件入参
155
244
  */
156
245
  interface Props {
157
- shape: Shape
246
+ shape: Shape;
158
247
  }
159
248
 
160
- const props = defineProps<Props>()
249
+ const props = defineProps<Props>();
161
250
 
162
251
  /**
163
252
  * 前端内置固定列:序号列
164
253
  */
165
254
  const indexColumn = {
166
- configId: 'index',
167
- name: '序号',
168
- isShow: true,
169
- isReadonly: false,
170
- }
255
+ configId: "index",
256
+ name: "序号",
257
+ isShow: true,
258
+ isReadonly: false,
259
+ };
171
260
  /**
172
261
  * 当前组件内部使用的行数据类型
173
262
  * 允许动态字段,便于适配后端返回的任意列
174
263
  */
175
264
  // 列宽度状态(动态调整,使用 configId 作为 key)
176
- const columnWidths = ref<Record<string, number>>({})
265
+ const columnWidths = ref<Record<string, number>>({});
177
266
  /**
178
267
  * 搜索输入框 ref
179
268
  */
180
- const searchInputRef = ref<HTMLInputElement | null>(null)
269
+ const searchInputRef = ref<HTMLInputElement | null>(null);
181
270
 
182
271
  /**
183
272
  * 表格容器 ref(用于虚拟滚动)
184
273
  */
185
- const tableContainerRef = ref<HTMLDivElement | null>(null)
274
+ const tableContainerRef = ref<HTMLDivElement | null>(null);
186
275
 
187
276
  /**
188
277
  * 当前编辑中的输入框 ref
189
278
  */
190
- const editingInputRef = ref<HTMLInputElement | null>(null)
279
+ const editingInputRef = ref<HTMLInputElement | null>(null);
191
280
 
192
281
  /**
193
282
  * 搜索相关状态
194
283
  */
195
- const showSearchBar = ref(false)
196
- const searchKeyword = ref('')
197
- const searchMatchedIds = ref<string[]>([])
198
- const currentMatchIndex = ref(-1)
284
+ const showSearchBar = ref(false);
285
+ const searchKeyword = ref("");
286
+ const searchMatchedIds = ref<string[]>([]);
287
+ const currentMatchIndex = ref(-1);
199
288
  /**
200
289
  * 默认列配置
201
290
  * 没有后端列配置时,使用这组默认列
202
291
  */
203
- const defaultColumns = ref<GanttColumn[]>([])
292
+ const defaultColumns = ref<GanttColumn[]>([]);
204
293
 
205
294
  // 甘特图数据:使用后端数据
206
- type GanttItem = GanttData & { hasChildren: boolean }
207
- const ganttItems = ref<GanttItem[]>([])
295
+ type GanttItem = GanttData & { hasChildren: boolean };
296
+ const ganttItems = ref<GanttItem[]>([]);
208
297
  /**
209
298
  * 除序号列之外的第一列 configId(displayColumns[1])
210
299
  */
211
300
  const firstDataColId = computed(() => {
212
- return displayColumns.value[1]?.configId || ''
213
- })
301
+ return displayColumns.value[1]?.configId || "";
302
+ });
214
303
  /**
215
304
  * 实际表格数据
216
305
  * 优先使用后端数据,没有则使用 mock 数据
@@ -218,753 +307,887 @@ const firstDataColId = computed(() => {
218
307
  // const ganttItems = ref<GanttItem[]>([...mockData.value])
219
308
 
220
309
  // 列配置:优先使用后端数据
221
- const columnConfig = ref<any[]>([...defaultColumns.value])
310
+ const columnConfig = ref<any[]>([...defaultColumns.value]);
222
311
 
223
312
  /**
224
313
  * 当前可见列
225
314
  */
226
315
  const visibleColumns = computed(() => {
227
- return columnConfig.value.filter(col => col.isShow)
228
- })
316
+ return columnConfig.value.filter((col) => col.isShow);
317
+ });
229
318
  /**
230
319
  * 最终渲染列
231
320
  * 序号列固定在最左侧
232
321
  */
233
322
  const displayColumns = computed(() => {
234
- return [indexColumn, ...visibleColumns.value]
235
- })
323
+ return [indexColumn, ...visibleColumns.value];
324
+ });
236
325
 
237
326
  /**
238
327
  * 过滤后的数据(用于搜索)
239
328
  * 如果没有搜索关键字,返回所有数据
240
329
  */
241
330
  const filteredGanttItems = computed(() => {
242
- const keyword = searchKeyword.value.trim().toLowerCase()
243
- if (!keyword) {
244
- return ganttItems.value
245
- }
331
+ const keyword = searchKeyword.value.trim().toLowerCase();
332
+ if (!keyword) {
333
+ return ganttItems.value;
334
+ }
246
335
 
247
- if (searchMatchedIds.value.length === 0) {
248
- return []
249
- }
336
+ if (searchMatchedIds.value.length === 0) {
337
+ return [];
338
+ }
250
339
 
251
- return ganttItems.value.filter(item => searchMatchedIds.value.includes(item.id))
252
- })
340
+ return ganttItems.value.filter((item) =>
341
+ searchMatchedIds.value.includes(item.id),
342
+ );
343
+ });
253
344
 
254
345
  // ========== 虚拟滚动 ==========
255
- const TABLE_HEADER_HEIGHT = 28
256
- const TABLE_ROW_HEIGHT = 32
257
- const TABLE_VIRTUAL_OVERSCAN = 8
346
+ const TABLE_HEADER_HEIGHT = 28;
347
+ const TABLE_ROW_HEIGHT = 32;
348
+ const TABLE_VIRTUAL_OVERSCAN = 8;
258
349
 
259
350
  const {
260
- virtualRows,
261
- virtualTopSpacerHeight,
262
- virtualBottomSpacerHeight,
263
- virtualStartIndex,
264
- virtualEndIndex,
265
- syncVirtualViewportState,
266
- visibleColumnSpan,
351
+ virtualRows,
352
+ virtualTopSpacerHeight,
353
+ virtualBottomSpacerHeight,
354
+ virtualStartIndex,
355
+ virtualEndIndex,
356
+ syncVirtualViewportState,
357
+ visibleColumnSpan,
267
358
  } = useVirtualScroll(filteredGanttItems, {
268
- itemHeight: TABLE_ROW_HEIGHT,
269
- headerHeight: TABLE_HEADER_HEIGHT,
270
- overscan: TABLE_VIRTUAL_OVERSCAN,
271
- containerRef: tableContainerRef,
272
- columnCount: computed(() => displayColumns.value.length),
273
- })
359
+ itemHeight: TABLE_ROW_HEIGHT,
360
+ headerHeight: TABLE_HEADER_HEIGHT,
361
+ overscan: TABLE_VIRTUAL_OVERSCAN,
362
+ containerRef: tableContainerRef,
363
+ columnCount: computed(() => displayColumns.value.length),
364
+ });
274
365
 
275
366
  /**
276
367
  * 监听虚拟索引变化,自动关闭不可见行的编辑状态
277
368
  */
278
369
  watch([virtualStartIndex, virtualEndIndex], () => {
279
- if (!editingTextCell.value) return
370
+ if (!editingTextCell.value) return;
280
371
 
281
- const renderedIds = new Set(virtualRows.value.map(({ item }) => item.id))
282
- if (!renderedIds.has(editingTextCell.value.id)) {
283
- closeCellEditor()
284
- }
285
- })
372
+ const renderedIds = new Set(virtualRows.value.map(({ item }) => item.id));
373
+ if (!renderedIds.has(editingTextCell.value.id)) {
374
+ closeCellEditor();
375
+ }
376
+ });
286
377
 
287
378
  /**
288
379
  * 行交互状态
289
380
  * 统一复用表格/甘特图共享的行选择与右键菜单逻辑
290
381
  */
291
382
  const {
292
- canMoveDown,
293
- canMoveUp,
294
- clearSelection,
295
- contextMenuPosition,
296
- deleteRows,
297
- handleContextMenu,
298
- handleDeleteFromMenu,
299
- handleMoveDownFromMenu,
300
- handleMoveUpFromMenu,
301
- handlePropertyConfig,
302
- handleRemoveFromMenu,
303
- handleTreeHighlight,
304
- moveDown,
305
- moveUp,
306
- onRemoveSuccess,
307
- removeRows,
308
- selectLastRow,
309
- selectRow,
310
- selectedRowIds,
311
- showContextMenu,
383
+ canMoveDown,
384
+ canMoveUp,
385
+ clearSelection,
386
+ contextMenuPosition,
387
+ deleteRows,
388
+ handleContextMenu,
389
+ handleDeleteFromMenu,
390
+ handleMoveDownFromMenu,
391
+ handleMoveUpFromMenu,
392
+ handlePropertyConfig,
393
+ handleRemoveFromMenu,
394
+ handleTreeHighlight,
395
+ moveDown,
396
+ moveUp,
397
+ onRemoveSuccess,
398
+ removeRows,
399
+ selectLastRow,
400
+ selectRow,
401
+ selectedRowIds,
402
+ showContextMenu,
312
403
  } = useChartRowSelection<GanttItem>({
313
- items: ganttItems,
314
- rowSelectedEvent: 'table-row-selected',
315
- onClearSelection: () => {
316
- closeCellEditor()
317
- },
318
- onDeleteRows: () => {
319
- closeCellEditor()
320
- },
321
- onAfterRemoveSuccess: () => {
322
- closeCellEditor()
323
- },
324
- })
325
-
326
- /**
327
- * 当前编辑中的单元格
328
- * 增加 editorType / column 信息,便于根据 valueType 渲染不同编辑控件
329
- */
404
+ items: ganttItems,
405
+ rowSelectedEvent: "table-row-selected",
406
+ onClearSelection: () => {
407
+ closeCellEditor();
408
+ },
409
+ onDeleteRows: () => {
410
+ closeCellEditor();
411
+ },
412
+ onAfterRemoveSuccess: () => {
413
+ closeCellEditor();
414
+ },
415
+ });
416
+
417
+ /**
418
+ * 当前编辑中的单元格
419
+ * 增加 editorType / column 信息,便于根据 valueType 渲染不同编辑控件
420
+ */
330
421
  const editingTextCell = ref<{
331
- id: string
332
- field: string
333
- value: any
334
- editorType?: string
335
- column?: any
336
- } | null>(null)
422
+ id: string;
423
+ field: string;
424
+ value: any;
425
+ editorType?: string;
426
+ column?: any;
427
+ } | null>(null);
337
428
 
338
429
  // 根据 configId 获取默认列宽
339
430
  function getDefaultColumnWidth(configId: string): number {
340
- if (configId === 'index') {
341
- return 50
342
- }
343
- // 其他列默认中等宽度
344
- return 400
431
+ if (configId === "index") {
432
+ return 50;
433
+ }
434
+ // 其他列默认中等宽度
435
+ return 400;
345
436
  }
346
437
  function getColumnWidth(configId: string): number {
347
- if (configId === 'index') {
348
- return 50
349
- }
350
- return columnWidths.value[configId] || getDefaultColumnWidth(configId)
438
+ if (configId === "index") {
439
+ return 50;
440
+ }
441
+ return columnWidths.value[configId] || getDefaultColumnWidth(configId);
351
442
  }
352
443
 
353
444
  /**
354
445
  * 点击空白区域,清空选中并关闭编辑态
355
446
  */
356
447
  function onContainerClick() {
357
- clearSelection()
448
+ clearSelection();
358
449
  }
359
450
  /**
360
451
  * 新增行
361
452
  */
362
453
  function addRow() {
363
- eventBus.emit('table-add-row')
454
+ eventBus.emit("table-add-row");
364
455
  }
365
456
  /**
366
457
  * 搜索结果显示文本
367
458
  */
368
459
  const searchResultText = computed(() => {
369
- if (!searchKeyword.value.trim()) return ''
370
- if (searchMatchedIds.value.length === 0) return '0 of 0'
371
- return `${currentMatchIndex.value + 1} of ${searchMatchedIds.value.length}`
372
- })
460
+ if (!searchKeyword.value.trim()) return "";
461
+ if (searchMatchedIds.value.length === 0) return "0 of 0";
462
+ return `${currentMatchIndex.value + 1} of ${searchMatchedIds.value.length}`;
463
+ });
373
464
 
374
465
  /**
375
466
  * 上一条 / 下一条按钮状态
376
467
  */
377
468
  const canGoPrev = computed(() => {
378
- return searchMatchedIds.value.length > 0 && currentMatchIndex.value > 0
379
- })
469
+ return searchMatchedIds.value.length > 0 && currentMatchIndex.value > 0;
470
+ });
380
471
 
381
472
  const canGoNext = computed(() => {
382
- return (
383
- searchMatchedIds.value.length > 0 &&
384
- currentMatchIndex.value < searchMatchedIds.value.length - 1
385
- )
386
- })
473
+ return (
474
+ searchMatchedIds.value.length > 0 &&
475
+ currentMatchIndex.value < searchMatchedIds.value.length - 1
476
+ );
477
+ });
387
478
 
388
479
  /**
389
480
  * 执行搜索
390
481
  * 搜索范围为当前可见列
391
482
  */
392
483
  function runSearch() {
393
- const keyword = searchKeyword.value.trim().toLowerCase()
394
- if (!keyword) {
395
- searchMatchedIds.value = []
396
- currentMatchIndex.value = -1
397
- return
398
- }
399
-
400
- // 模糊匹配:搜索所有可见列的值
401
- const matched = ganttItems.value.filter(item => {
402
- return visibleColumns.value.some(col => {
403
- const value = getDisplayCellValue(item, col)
404
- return value.toLowerCase().includes(keyword)
405
- })
406
- })
407
-
408
- searchMatchedIds.value = matched.map(item => item.id)
409
- currentMatchIndex.value = searchMatchedIds.value.length > 0 ? 0 : -1
410
-
411
- // 自动选中第一个匹配项
412
- if (currentMatchIndex.value >= 0) {
413
- selectRow(searchMatchedIds.value[0])
414
- }
484
+ const keyword = searchKeyword.value.trim().toLowerCase();
485
+ if (!keyword) {
486
+ searchMatchedIds.value = [];
487
+ currentMatchIndex.value = -1;
488
+ return;
489
+ }
490
+
491
+ // 模糊匹配:搜索所有可见列的值
492
+ const matched = ganttItems.value.filter((item) => {
493
+ return visibleColumns.value.some((col) => {
494
+ const value = getDisplayCellValue(item, col);
495
+ return value.toLowerCase().includes(keyword);
496
+ });
497
+ });
498
+
499
+ searchMatchedIds.value = matched.map((item) => item.id);
500
+ currentMatchIndex.value = searchMatchedIds.value.length > 0 ? 0 : -1;
501
+
502
+ // 自动选中第一个匹配项
503
+ if (currentMatchIndex.value >= 0) {
504
+ selectRow(searchMatchedIds.value[0]);
505
+ }
415
506
  }
416
507
 
417
508
  /**
418
509
  * 搜索输入事件
419
510
  */
420
511
  function onSearchInput() {
421
- runSearch()
512
+ runSearch();
422
513
  }
423
514
 
424
515
  /**
425
516
  * 跳转上一条匹配
426
517
  */
427
518
  function gotoPrevMatch() {
428
- if (!canGoPrev.value) return
429
- currentMatchIndex.value--
430
- selectRow(searchMatchedIds.value[currentMatchIndex.value])
519
+ if (!canGoPrev.value) return;
520
+ currentMatchIndex.value--;
521
+ selectRow(searchMatchedIds.value[currentMatchIndex.value]);
431
522
  }
432
523
 
433
524
  /**
434
525
  * 跳转下一条匹配
435
526
  */
436
527
  function gotoNextMatch() {
437
- if (!canGoNext.value) return
438
- currentMatchIndex.value++
439
- selectRow(searchMatchedIds.value[currentMatchIndex.value])
528
+ if (!canGoNext.value) return;
529
+ currentMatchIndex.value++;
530
+ selectRow(searchMatchedIds.value[currentMatchIndex.value]);
440
531
  }
441
532
 
442
533
  /**
443
534
  * 打开搜索栏
444
535
  */
445
536
  function openSearch() {
446
- showSearchBar.value = true
447
- nextTick(() => {
448
- searchInputRef.value?.focus()
449
- })
537
+ showSearchBar.value = true;
538
+ nextTick(() => {
539
+ searchInputRef.value?.focus();
540
+ });
450
541
  }
451
542
 
452
543
  /**
453
544
  * 关闭搜索栏
454
545
  */
455
546
  function closeSearch() {
456
- showSearchBar.value = false
457
- searchKeyword.value = ''
458
- searchMatchedIds.value = []
459
- currentMatchIndex.value = -1
547
+ showSearchBar.value = false;
548
+ searchKeyword.value = "";
549
+ searchMatchedIds.value = [];
550
+ currentMatchIndex.value = -1;
460
551
  }
461
552
 
462
553
  /**
463
554
  * 工具栏指令监听
464
555
  */
465
556
  function onGanttToolbarAction(action: string) {
466
- const actionMap: Record<string, () => void> = {
467
- chartNewModel: addRow,
468
- chartDelete: deleteRows,
469
- chartRemove: removeRows,
470
- chartMoveUp: moveUp,
471
- chartMoveDown: moveDown,
472
- chartSearch: openSearch,
473
- }
474
- const fn = actionMap[action]
475
- if (!fn) return
476
- fn()
557
+ const actionMap: Record<string, () => void> = {
558
+ chartNewModel: addRow,
559
+ chartDelete: deleteRows,
560
+ chartRemove: removeRows,
561
+ chartMoveUp: moveUp,
562
+ chartMoveDown: moveDown,
563
+ chartSearch: openSearch,
564
+ };
565
+ const fn = actionMap[action];
566
+ if (!fn) return;
567
+ fn();
477
568
  }
478
569
  /**
479
570
  * 判断当前单元格是否正在编辑
480
571
  */
481
572
  function isCellEditing(rowId: string, field: string) {
482
- return editingTextCell.value?.id === rowId && editingTextCell.value?.field === field
573
+ return (
574
+ editingTextCell.value?.id === rowId &&
575
+ editingTextCell.value?.field === field
576
+ );
483
577
  }
484
578
 
485
579
  /**
486
580
  * 设置当前编辑输入框 ref
487
581
  */
488
582
  function setEditingInputRef(el: HTMLInputElement | null | any) {
489
- editingInputRef.value = el
583
+ editingInputRef.value = el;
490
584
  }
491
585
 
492
586
  /**
493
- * 打开单元格编辑
494
- * 根据列的 valueType 选择合适的编辑控件
495
- */
587
+ * 打开单元格编辑
588
+ * 根据列的 valueType 选择合适的编辑控件
589
+ */
496
590
  function openCellEditor(item: GanttItem, col: any) {
497
- if (col.isReadonly === true) return
498
-
499
- // 原始值直接从数据行中读取,避免使用展示值(例如枚举的 label)
500
- const rawValue = (item as any)[col.configId]
501
-
502
- // 复杂类型:交给宿主应用使用“属性面板同款编辑器”处理
503
- // 这样 graph 包保持轻量,不强依赖业务侧的弹窗/选择器实现
504
- // 复杂值类型不走表格内联编辑,统一交给宿主侧弹出属性面板同款编辑器。
505
- // Transfer 在业务上对应“选择用例”穿梭框,双击单元格时也要走这条链路。
506
- const complexTypes = new Set([
507
- 'Element',
508
- 'Element_List',
509
- 'Relations_End',
510
- 'ValueSpecification',
511
- 'NoString',
512
- 'Transfer',
513
- ])
514
- if (complexTypes.has(col.valueType)) {
515
- eventBus.emit('table-cell-open-editor', {
516
- item,
517
- column: col,
518
- configId: col.configId,
519
- valueType: col.valueType,
520
- value: rawValue ?? null,
521
- })
522
- return
523
- }
524
-
525
- editingTextCell.value = {
526
- id: item.id,
527
- field: col.configId,
528
- value: rawValue ?? '',
529
- editorType: col.valueType,
530
- column: col,
531
- }
532
- nextTick(() => {
533
- const inst = editingInputRef.value as any
534
- inst?.focus?.()
535
- inst?.select?.()
536
- })
591
+ if (col.isReadonly === true) return;
592
+ if (!hasCellProperty(item, col.configId)) return;
593
+
594
+ // 原始值直接从数据行中读取,避免使用展示值(例如枚举的 label)
595
+ const rawValue = (item as any)[col.configId];
596
+
597
+ console.log("[graph-table-openCellEditor] valueType:", col.valueType, {
598
+ configId: col.configId,
599
+ column: col,
600
+ value: rawValue ?? null,
601
+ });
602
+
603
+ if (col.valueType === "Boolean") {
604
+ return;
605
+ }
606
+
607
+ // 复杂类型:交给宿主应用使用“属性面板同款编辑器”处理
608
+ // 这样 graph 包保持轻量,不强依赖业务侧的弹窗/选择器实现
609
+ // 复杂值类型不走表格内联编辑,统一交给宿主侧弹出属性面板同款编辑器。
610
+ // Transfer 在业务上对应“选择用例”穿梭框,双击单元格时也要走这条链路。
611
+ const complexTypes = new Set([
612
+ "Element",
613
+ "Element_List",
614
+ "Relations_End",
615
+ "ValueSpecification",
616
+ "NoString",
617
+ "Transfer",
618
+ "Html",
619
+ "Htmld",
620
+ ]);
621
+ if (complexTypes.has(col.valueType)) {
622
+ eventBus.emit("table-cell-open-editor", {
623
+ item,
624
+ column: col,
625
+ configId: col.configId,
626
+ valueType: col.valueType,
627
+ value: rawValue ?? null,
628
+ });
629
+ return;
630
+ }
631
+
632
+ editingTextCell.value = {
633
+ id: item.id,
634
+ field: col.configId,
635
+ value: rawValue ?? "",
636
+ editorType: col.valueType,
637
+ column: col,
638
+ };
639
+ nextTick(() => {
640
+ const inst = editingInputRef.value as any;
641
+ inst?.focus?.();
642
+ inst?.select?.();
643
+ });
537
644
  }
538
645
 
539
646
  function getRawCellValue(item: any, configId: string) {
540
- const v = item?.[configId]
541
- return v
647
+ const v = item?.[configId];
648
+ return v;
542
649
  }
543
650
 
544
- /**
545
- * 保存单元格值
546
- */
547
- function saveTextEdit(item: GanttItem, field: string) {
651
+ function hasCellProperty(item: any, configId: string): boolean {
652
+ return !!item && Object.prototype.hasOwnProperty.call(item, configId);
653
+ }
548
654
 
549
- if (!editingTextCell.value || editingTextCell.value.value === undefined) {
550
- editingTextCell.value = null
551
- return
552
- }
655
+ function normalizeBooleanValue(value: any): boolean | undefined {
656
+ if (value === null || value === undefined || value === "") {
657
+ return undefined;
658
+ }
553
659
 
554
- const oldValue = getRawCellValue(item as any, field)
555
- const newValue = editingTextCell.value.value
660
+ if (typeof value === "boolean") {
661
+ return value;
662
+ }
556
663
 
557
- // 值未改变,直接关闭编辑
558
- if (oldValue === newValue) {
559
- editingTextCell.value = null
560
- return
561
- }
664
+ if (typeof value === "string") {
665
+ if (value === "true") return true;
666
+ if (value === "false") return false;
667
+ if (value === "1") return true;
668
+ if (value === "0") return false;
669
+ }
670
+
671
+ if (typeof value === "number") {
672
+ if (value === 1) return true;
673
+ if (value === 0) return false;
674
+ }
675
+
676
+ return undefined;
677
+ }
562
678
 
563
- // 发送编辑事件到父组件(与 Gantt 使用相同的事件名)
564
- eventBus.emit('gantt-cell-edit', {
565
- item,
566
- configId: field,
567
- oldValue,
568
- newValue
569
- })
679
+ function hasBooleanCellValue(item: any, configId: string): boolean {
680
+ if (!hasCellProperty(item, configId)) {
681
+ return false;
682
+ }
570
683
 
571
- // 暂时关闭编辑状态(等待接口返回)
572
- editingTextCell.value = null
684
+ return normalizeBooleanValue(item[configId]) !== undefined;
685
+ }
686
+
687
+ function stripHtmlTags(value: unknown): string {
688
+ return String(value ?? "")
689
+ .replace(/<[^>]+>/g, "")
690
+ .replace(/&nbsp;/gi, " ")
691
+ .replace(/\s+/g, " ")
692
+ .trim();
693
+ }
694
+
695
+ function handleBooleanCellChange(
696
+ item: GanttItem,
697
+ field: string,
698
+ value: string | number | boolean | undefined,
699
+ ) {
700
+ if (!hasBooleanCellValue(item, field)) {
701
+ return;
702
+ }
703
+
704
+ const oldValue = getRawCellValue(item as any, field);
705
+ const normalizedOldValue = normalizeBooleanValue(oldValue);
706
+ const normalizedNewValue = normalizeBooleanValue(value);
707
+
708
+ if (normalizedOldValue === normalizedNewValue) {
709
+ return;
710
+ }
711
+
712
+ eventBus.emit("gantt-cell-edit", {
713
+ item,
714
+ configId: field,
715
+ oldValue,
716
+ newValue: normalizedNewValue,
717
+ });
718
+ }
719
+
720
+ /**
721
+ * 保存单元格值
722
+ */
723
+ function saveTextEdit(item: GanttItem, field: string) {
724
+ if (!editingTextCell.value || editingTextCell.value.value === undefined) {
725
+ editingTextCell.value = null;
726
+ return;
727
+ }
728
+
729
+ const oldValue = getRawCellValue(item as any, field);
730
+ const newValue = editingTextCell.value.value;
731
+
732
+ // 值未改变,直接关闭编辑
733
+ if (oldValue === newValue) {
734
+ editingTextCell.value = null;
735
+ return;
736
+ }
737
+
738
+ // 发送编辑事件到父组件(与 Gantt 使用相同的事件名)
739
+ eventBus.emit("gantt-cell-edit", {
740
+ item,
741
+ configId: field,
742
+ oldValue,
743
+ newValue,
744
+ });
745
+
746
+ // 暂时关闭编辑状态(等待接口返回)
747
+ editingTextCell.value = null;
573
748
  }
574
749
 
575
750
  /**
576
751
  * 关闭单元格编辑
577
752
  */
578
753
  function closeCellEditor() {
579
- editingTextCell.value = null
580
- editingInputRef.value = null
754
+ editingTextCell.value = null;
755
+ editingInputRef.value = null;
581
756
  }
582
757
  //监听获取后端列配置
583
- watch(() => props.shape.attributeColumns, (columns) => {
758
+ watch(
759
+ () => props.shape.attributeColumns,
760
+ (columns) => {
584
761
  if (columns && columns.length > 0) {
585
- columnConfig.value = columns
586
- // 初始化列宽(如果还没有设置)
587
- columns.forEach((col: any) => {
588
- if (col.configId !== 'index' && !columnWidths.value[col.configId]) {
589
- columnWidths.value[col.configId] = getDefaultColumnWidth(col.configId)
590
- }
591
- })
592
- // 同步到工具栏菜单
593
- eventBus.emit('chart-columns-from-backend', columns)
762
+ columnConfig.value = columns;
763
+ // 初始化列宽(如果还没有设置)
764
+ columns.forEach((col: any) => {
765
+ if (col.configId !== "index" && !columnWidths.value[col.configId]) {
766
+ columnWidths.value[col.configId] = getDefaultColumnWidth(
767
+ col.configId,
768
+ );
769
+ }
770
+ });
771
+ // 同步到工具栏菜单
772
+ eventBus.emit("chart-columns-from-backend", columns);
594
773
  } else {
595
- // 没有后端数据时使用默认配置
596
- columnConfig.value = [...defaultColumns.value]
774
+ // 没有后端数据时使用默认配置
775
+ columnConfig.value = [...defaultColumns.value];
597
776
  }
598
- }, { immediate: true })
777
+ },
778
+ { immediate: true },
779
+ );
599
780
  // 统一提取对象/对象数组类型单元格的展示文本和图标,避免 Element_List 展示成 [object Object]。
600
781
  function getCellDisplayMeta(value: any): { text: string; icon: string } {
601
- if (Array.isArray(value)) {
602
- const objectItems = value.filter((item) => item && typeof item === 'object')
603
- const text = objectItems
604
- .map((item: any) => item.nodeName || item.modelName || '')
605
- .filter(Boolean)
606
- .join('、')
607
-
608
- return {
609
- text: text || String(value ?? ''),
610
- icon: objectItems.find((item: any) => item.icon)?.icon || '',
611
- }
612
- }
782
+ if (Array.isArray(value)) {
783
+ const objectItems = value.filter(
784
+ (item) => item && typeof item === "object",
785
+ );
786
+ const text = objectItems
787
+ .map((item: any) => item.nodeName || item.modelName || "")
788
+ .filter(Boolean)
789
+ .join("、");
613
790
 
614
- if (value && typeof value === 'object') {
615
- return {
616
- text: value.nodeName || value.modelName || String(value ?? ''),
617
- icon: value.icon || '',
618
- }
619
- }
791
+ return {
792
+ text: text || String(value ?? ""),
793
+ icon: objectItems.find((item: any) => item.icon)?.icon || "",
794
+ };
795
+ }
620
796
 
797
+ if (value && typeof value === "object") {
621
798
  return {
622
- text: String(value ?? ''),
623
- icon: '',
624
- }
799
+ text: value.nodeName || value.modelName || String(value ?? ""),
800
+ icon: value.icon || "",
801
+ };
802
+ }
803
+
804
+ return {
805
+ text: String(value ?? ""),
806
+ icon: "",
807
+ };
625
808
  }
626
809
 
627
810
  // 根据列配置获取“展示值”(用于单元格展示 / title)
628
- function getDisplayCellValue(item: GanttData & { hasChildren: boolean }, col: any): string {
629
- const configId = col.configId
630
- const value = (item as any)[configId]
631
-
632
- if (col.valueType === 'Boolean') {
633
- if (value === true) return '是'
634
- if (value === false) return '否'
635
- return ''
636
- }
637
-
638
- // 枚举类型:用 literals 中的 key 作为展示文案
639
- if (col.valueType === 'Enumeration' && col.literals && Array.isArray(col.literals)) {
640
- const matched = col.literals.find((opt: any) => opt.value === value)
641
- return matched?.key ?? String(value ?? '')
642
- }
643
-
644
- return getCellDisplayMeta(value).text
811
+ function getDisplayCellValue(
812
+ item: GanttData & { hasChildren: boolean },
813
+ col: any,
814
+ ): string {
815
+ const configId = col.configId;
816
+ const value = (item as any)[configId];
817
+
818
+ if (col.valueType === "Html" || col.valueType === "Htmld") {
819
+ return stripHtmlTags(value);
820
+ }
821
+
822
+ if (col.valueType === "Boolean") {
823
+ const normalizedValue = normalizeBooleanValue(value);
824
+ if (normalizedValue === true) return "是";
825
+ if (normalizedValue === false) return "否";
826
+ return "";
827
+ }
828
+
829
+ // 枚举类型:用 literals 中的 key 作为展示文案
830
+ if (
831
+ col.valueType === "Enumeration" &&
832
+ col.literals &&
833
+ Array.isArray(col.literals)
834
+ ) {
835
+ const matched = col.literals.find((opt: any) => opt.value === value);
836
+ return matched?.key ?? String(value ?? "");
837
+ }
838
+
839
+ return getCellDisplayMeta(value).text;
645
840
  }
646
841
 
647
842
  // 获取单元格应展示的图标。
648
843
  // 第一列仍然优先展示行本身图标,其他对象/对象数组列则展示值里的 icon。
649
- function getDisplayCellIcon(item: GanttData & { hasChildren: boolean }, col: any): string {
650
- if (col.configId === firstDataColId.value && item.icon) {
651
- return item.icon
652
- }
653
-
654
- return getCellDisplayMeta((item as any)[col.configId]).icon
844
+ function getDisplayCellIcon(
845
+ item: GanttData & { hasChildren: boolean },
846
+ col: any,
847
+ ): string {
848
+ if (col.configId === firstDataColId.value && item.icon) {
849
+ return item.icon;
850
+ }
851
+
852
+ return getCellDisplayMeta((item as any)[col.configId]).icon;
655
853
  }
656
854
  // 根据 configId 获取“原始值”(用于比较 old/new、搜索等)
657
- function getCellValue(item: GanttData & { hasChildren: boolean }, configId: string): string {
658
- return getCellDisplayMeta((item as any)[configId]).text
855
+ function getCellValue(
856
+ item: GanttData & { hasChildren: boolean },
857
+ configId: string,
858
+ ): string {
859
+ return getCellDisplayMeta((item as any)[configId]).text;
659
860
  }
660
861
  // 列宽调整
661
862
  function startColumnResize(columnKey: string, e: MouseEvent) {
662
- if (columnKey === 'index') return
663
-
664
- e.stopPropagation()
665
- e.preventDefault()
666
-
667
- const startX = e.clientX
668
- const startWidth = getColumnWidth(columnKey)
669
-
670
- const onMove = (ev: MouseEvent) => {
671
- const delta = ev.clientX - startX
672
- const nextWidth = Math.max(200, startWidth + delta)
673
- columnWidths.value[columnKey] = nextWidth
674
- }
675
-
676
- const onUp = () => {
677
- document.removeEventListener('mousemove', onMove)
678
- document.removeEventListener('mouseup', onUp)
679
- document.body.style.cursor = ''
680
- document.body.style.userSelect = ''
681
- }
682
-
683
- document.body.style.cursor = 'col-resize'
684
- document.body.style.userSelect = 'none'
685
- document.addEventListener('mousemove', onMove)
686
- document.addEventListener('mouseup', onUp)
863
+ if (columnKey === "index") return;
864
+
865
+ e.stopPropagation();
866
+ e.preventDefault();
867
+
868
+ const startX = e.clientX;
869
+ const startWidth = getColumnWidth(columnKey);
870
+
871
+ const onMove = (ev: MouseEvent) => {
872
+ const delta = ev.clientX - startX;
873
+ const nextWidth = Math.max(200, startWidth + delta);
874
+ columnWidths.value[columnKey] = nextWidth;
875
+ };
876
+
877
+ const onUp = () => {
878
+ document.removeEventListener("mousemove", onMove);
879
+ document.removeEventListener("mouseup", onUp);
880
+ document.body.style.cursor = "";
881
+ document.body.style.userSelect = "";
882
+ };
883
+
884
+ document.body.style.cursor = "col-resize";
885
+ document.body.style.userSelect = "none";
886
+ document.addEventListener("mousemove", onMove);
887
+ document.addEventListener("mouseup", onUp);
687
888
  }
688
889
  function handleCanvasColumnChange(columns: any[]) {
689
- if (columns && columns.length > 0) {
690
- columnConfig.value = columns
691
-
692
- // 初始化列宽(如果还没有设置)
693
- columns.forEach((col: any) => {
694
- if (col.configId !== 'index' && !columnWidths.value[col.configId]) {
695
- columnWidths.value[col.configId] = getDefaultColumnWidth(col.configId)
696
- }
697
- })
698
-
699
- // 同步到工具栏菜单
700
- // eventBus.emit('chart-columns-from-backend', columns)
701
- }
890
+ if (columns && columns.length > 0) {
891
+ columnConfig.value = columns;
892
+
893
+ // 初始化列宽(如果还没有设置)
894
+ columns.forEach((col: any) => {
895
+ if (col.configId !== "index" && !columnWidths.value[col.configId]) {
896
+ columnWidths.value[col.configId] = getDefaultColumnWidth(col.configId);
897
+ }
898
+ });
899
+
900
+ // 同步到工具栏菜单
901
+ // eventBus.emit('chart-columns-from-backend', columns)
902
+ }
702
903
  }
703
904
 
704
905
  // 监听后端数据变化
705
906
  function handleCanvasDataChange(data: any[]) {
706
- if (data && data.length > 0) {
707
- ganttItems.value = data.map(d => ({ ...d, hasChildren: false })) as (GanttData & { hasChildren: boolean })[]
708
- }
907
+ if (data && data.length > 0) {
908
+ ganttItems.value = data.map((d) => ({
909
+ ...d,
910
+ hasChildren: false,
911
+ })) as (GanttData & { hasChildren: boolean })[];
912
+ }
709
913
  }
710
914
 
711
915
  // 监听列配置变更(来自工具栏菜单)
712
916
  function onColumnConfigChange(config: Array<any>) {
713
- columnConfig.value = config
917
+ columnConfig.value = config;
714
918
  }
715
919
  const tableWidth = computed(() => {
716
- return displayColumns.value.reduce((total, col) => {
717
- return total + getColumnWidth(col.configId)
718
- }, 0)
719
- })
920
+ return displayColumns.value.reduce((total, col) => {
921
+ return total + getColumnWidth(col.configId);
922
+ }, 0);
923
+ });
720
924
  /**
721
925
  * 生命周期:注册事件
722
926
  */
723
927
  onMounted(() => {
724
- eventBus.on('table-toolbar-action', onGanttToolbarAction)
725
- eventBus.on('canvas-data-change', handleCanvasDataChange)
726
- eventBus.on('chart-column-config', onColumnConfigChange)
727
- eventBus.on('canvas-data-column', handleCanvasColumnChange)
728
- //监听移除成功事件
729
- eventBus.on('table-gantt-remove:success', onRemoveSuccess)
730
- // 新增成功回执:直接选中最后一条
731
- eventBus.on('table-gantt-add:success', selectLastRow)
732
- })
928
+ eventBus.on("table-toolbar-action", onGanttToolbarAction);
929
+ eventBus.on("canvas-data-change", handleCanvasDataChange);
930
+ eventBus.on("chart-column-config", onColumnConfigChange);
931
+ eventBus.on("canvas-data-column", handleCanvasColumnChange);
932
+ //监听移除成功事件
933
+ eventBus.on("table-gantt-remove:success", onRemoveSuccess);
934
+ // 新增成功回执:直接选中最后一条
935
+ eventBus.on("table-gantt-add:success", selectLastRow);
936
+ });
733
937
 
734
938
  /**
735
939
  * 生命周期:卸载事件
736
940
  */
737
941
  onUnmounted(() => {
738
- eventBus.off('table-toolbar-action', onGanttToolbarAction)
739
- eventBus.off('canvas-data-change', handleCanvasDataChange)
740
- eventBus.off('chart-column-config', onColumnConfigChange)
741
- eventBus.off('canvas-data-column', handleCanvasColumnChange)
742
- eventBus.off('table-gantt-remove:success', onRemoveSuccess)
743
- eventBus.off('table-gantt-add:success', selectLastRow)
744
- })
942
+ eventBus.off("table-toolbar-action", onGanttToolbarAction);
943
+ eventBus.off("canvas-data-change", handleCanvasDataChange);
944
+ eventBus.off("chart-column-config", onColumnConfigChange);
945
+ eventBus.off("canvas-data-column", handleCanvasColumnChange);
946
+ eventBus.off("table-gantt-remove:success", onRemoveSuccess);
947
+ eventBus.off("table-gantt-add:success", selectLastRow);
948
+ });
745
949
  </script>
746
950
 
747
951
  <style scoped lang="scss">
748
952
  /* 甘特表格容器 */
749
953
  .gantt-container {
750
- --header-row-h: 28px;
751
- --data-row-h: 32px;
752
-
753
- position: relative;
754
- display: flex;
755
- width: 100%;
756
- height: 100%;
757
- border: 1px solid #dcdfe6;
758
- background: #fff;
759
- overflow: hidden;
760
- font-size: 12px;
761
- font-family: 'Source Han Sans SC', 'Microsoft YaHei', 'PingFang SC', Arial, sans-serif;
954
+ --header-row-h: 28px;
955
+ --data-row-h: 32px;
956
+
957
+ position: relative;
958
+ display: flex;
959
+ width: 100%;
960
+ height: 100%;
961
+ border: 1px solid #dcdfe6;
962
+ background: #fff;
963
+ overflow: hidden;
964
+ font-size: 12px;
965
+ font-family:
966
+ "Source Han Sans SC", "Microsoft YaHei", "PingFang SC", Arial, sans-serif;
762
967
  }
763
968
  /* 左侧表格区域 */
764
969
  .gantt-left {
765
- width: 100%;
766
- overflow: auto;
970
+ width: 100%;
971
+ overflow: auto;
767
972
  }
768
973
 
769
974
  .gantt-left.with-search-bar {
770
- margin-top: 36px;
975
+ margin-top: 36px;
771
976
  }
772
977
 
773
978
  /* 虚拟滚动占位行 */
774
979
  .table-spacer-row td {
775
- height: 0;
776
- padding: 0;
777
- border: none !important;
980
+ height: 0;
981
+ padding: 0;
982
+ border: none !important;
778
983
  }
779
984
 
780
985
  .table-spacer {
781
- width: 1px;
986
+ width: 1px;
782
987
  }
783
988
 
784
989
  /* 表格 */
785
990
  .gantt-table {
786
- border-collapse: separate;
787
- border-spacing: 0;
788
- table-layout: fixed;
991
+ border-collapse: separate;
992
+ border-spacing: 0;
993
+ table-layout: fixed;
789
994
  }
790
995
 
791
996
  .th-content {
792
- position: relative;
793
- display: flex;
794
- align-items: center;
795
- width: 100%;
796
- height: 100%;
797
- min-width: 0;
798
- padding: 0 8px;
799
- box-sizing: border-box;
997
+ position: relative;
998
+ display: flex;
999
+ align-items: center;
1000
+ width: 100%;
1001
+ height: 100%;
1002
+ min-width: 0;
1003
+ box-sizing: border-box;
1004
+ }
1005
+ .th-content > :nth-child(1) {
1006
+ margin-left: 4px;
800
1007
  }
801
-
802
1008
  .gantt-table th,
803
1009
  .gantt-table td {
804
- box-sizing: border-box;
805
- padding: 0 8px;
806
- border: none;
807
- border-bottom: 1px solid #ebeef5;
808
- border-right: 1px solid #ebeef5;
809
- text-align: left;
810
- vertical-align: middle;
811
- white-space: nowrap;
812
- overflow: hidden;
813
- text-overflow: ellipsis;
1010
+ box-sizing: border-box;
1011
+ padding: 0 8px;
1012
+ border: none;
1013
+ border-bottom: 1px solid #ebeef5;
1014
+ border-right: 1px solid #ebeef5;
1015
+ text-align: left;
1016
+ vertical-align: middle;
1017
+ white-space: nowrap;
1018
+ overflow: hidden;
1019
+ text-overflow: ellipsis;
814
1020
  }
815
1021
 
816
1022
  .gantt-table th:first-child,
817
1023
  .gantt-table td:first-child {
818
- border-left: 1px solid #ebeef5;
819
- width: 50px;
820
- min-width: 50px;
821
- max-width: 50px;
1024
+ border-left: 1px solid #ebeef5;
1025
+ width: 50px;
1026
+ min-width: 50px;
1027
+ max-width: 50px;
822
1028
  }
823
1029
 
824
-
825
1030
  /* 表头第二行 */
826
1031
  .header-row-2 th {
827
- position: sticky;
828
- z-index: 1;
829
- height: var(--header-row-h);
830
- background: #f5f7fa;
831
- border-bottom-color: #dcdfe6;
832
- font-weight: 500;
833
- color: #606266;
1032
+ position: sticky;
1033
+ z-index: 1;
1034
+ height: var(--header-row-h);
1035
+ background: #f5f7fa;
1036
+ border-bottom-color: #dcdfe6;
1037
+ font-weight: 500;
1038
+ color: #606266;
834
1039
  }
835
1040
 
836
1041
  /* 数据行 */
837
1042
  .gantt-table td {
838
- height: var(--data-row-h);
1043
+ height: var(--data-row-h);
839
1044
  }
840
1045
 
841
1046
  /* 列样式 */
842
1047
  .col-name {
843
- text-align: left;
1048
+ text-align: left;
844
1049
  }
845
1050
 
846
1051
  .col-td {
847
- text-align: center;
1052
+ text-align: center;
848
1053
  }
849
1054
 
850
1055
  .col-index {
851
- width: 60px !important;
1056
+ width: 60px !important;
852
1057
  }
853
1058
 
854
1059
  .th-label {
855
- font-weight: 600;
1060
+ font-weight: 600;
856
1061
  }
857
1062
  .cell-text {
858
- flex: 1;
859
- min-width: 0;
860
- overflow: hidden;
861
- text-overflow: ellipsis;
862
- white-space: nowrap;
1063
+ flex: 1;
1064
+ min-width: 0;
1065
+ overflow: hidden;
1066
+ text-overflow: ellipsis;
1067
+ white-space: nowrap;
863
1068
  }
864
1069
  /* 展开图标 */
865
1070
  .expand-icon {
866
- display: inline-block;
867
- margin-right: 4px;
868
- cursor: pointer;
869
- user-select: none;
1071
+ display: inline-block;
1072
+ margin-right: 4px;
1073
+ cursor: pointer;
1074
+ user-select: none;
870
1075
  }
871
1076
 
872
1077
  /* 名称文本 */
873
1078
  .item-name {
874
- display: inline-block;
875
- width: 100%;
876
- overflow: hidden;
877
- text-overflow: ellipsis;
878
- vertical-align: middle;
879
- display: flex;
880
- align-items: center;
881
- min-width: 0;
1079
+ display: inline-block;
1080
+ width: 100%;
1081
+ overflow: hidden;
1082
+ text-overflow: ellipsis;
1083
+ vertical-align: middle;
1084
+ display: flex;
1085
+ align-items: center;
1086
+ min-width: 0;
882
1087
  }
883
1088
 
884
1089
  .expand-icon {
885
- flex: 0 0 auto;
886
- display: inline-flex;
887
- align-items: center;
888
- justify-content: center;
889
- margin-right: 5px;
890
- cursor: pointer;
891
- user-select: none;
1090
+ flex: 0 0 auto;
1091
+ display: inline-flex;
1092
+ align-items: center;
1093
+ justify-content: center;
1094
+ margin-right: 5px;
1095
+ cursor: pointer;
1096
+ user-select: none;
892
1097
  }
893
1098
 
894
1099
  .item-index {
895
- text-align: center;
1100
+ text-align: center;
896
1101
  }
897
1102
 
898
1103
  /* 单元格编辑输入框(Element Plus 包一层外壳,尽量贴合现有样式) */
899
1104
  .cell-input {
900
- width: 100%;
1105
+ width: 100%;
901
1106
  }
902
1107
 
903
1108
  .cell-input :deep(.el-input__wrapper) {
904
- padding: 0 6px;
905
- height: 24px;
906
- box-shadow: 0 0 0 1px #409eff inset;
907
- border-radius: 3px;
1109
+ padding: 0 6px;
1110
+ height: 24px;
1111
+ box-shadow: 0 0 0 1px #409eff inset;
1112
+ border-radius: 3px;
908
1113
  }
909
1114
 
910
1115
  .cell-select {
911
- width: 100%;
1116
+ width: 100%;
912
1117
  }
913
1118
 
914
1119
  .cell-select :deep(.el-input__wrapper) {
915
- min-height: 24px;
916
- height: 24px;
917
- padding: 0 6px;
918
- border-radius: 3px;
1120
+ min-height: 24px;
1121
+ height: 24px;
1122
+ padding: 0 6px;
1123
+ border-radius: 3px;
1124
+ }
1125
+
1126
+ .cell-boolean-display {
1127
+ overflow: visible;
1128
+ }
1129
+
1130
+ .cell-boolean-group {
1131
+ display: inline-flex;
1132
+ align-items: center;
1133
+ height: 24px;
1134
+ }
1135
+
1136
+ .cell-boolean-group :deep(.el-radio) {
1137
+ align-items: center;
1138
+ margin-right: 10px;
1139
+ margin-bottom: 0;
1140
+ }
1141
+
1142
+ .cell-boolean-group :deep(.el-radio:last-child) {
1143
+ margin-right: 0;
919
1144
  }
920
1145
 
921
- .cell-switch {
922
- display: inline-flex;
923
- align-items: center;
924
- height: 24px;
1146
+ .cell-boolean-group :deep(.el-radio__label) {
1147
+ padding-left: 4px;
925
1148
  }
926
1149
 
927
1150
  .cell-date {
928
- width: 100%;
1151
+ width: 100%;
929
1152
  }
930
1153
 
931
1154
  .cell-date :deep(.el-input__wrapper) {
932
- min-height: 24px;
933
- height: 24px;
934
- padding: 0 6px;
935
- border-radius: 3px;
1155
+ min-height: 24px;
1156
+ height: 24px;
1157
+ padding: 0 6px;
1158
+ border-radius: 3px;
936
1159
  }
937
1160
 
938
1161
  .cell-textarea {
939
- width: 100%;
1162
+ width: 100%;
940
1163
  }
941
1164
 
942
1165
  .cell-textarea :deep(.el-textarea__inner) {
943
- font-size: 12px;
944
- line-height: 18px;
945
- padding: 4px 6px;
1166
+ font-size: 12px;
1167
+ line-height: 18px;
1168
+ padding: 4px 6px;
946
1169
  }
947
1170
 
948
1171
  .col-resizer {
949
- position: absolute;
950
- right: -8px;
951
- top: 0;
952
- bottom: 0;
953
- width: 5px;
954
- cursor: col-resize;
955
- user-select: none;
1172
+ position: absolute;
1173
+ right: -8px;
1174
+ top: 0;
1175
+ bottom: 0;
1176
+ width: 5px;
1177
+ cursor: col-resize;
1178
+ user-select: none;
956
1179
  }
957
1180
 
958
1181
  .col-resizer:hover {
959
- background-color: rgba(64, 158, 255, 0.1);
1182
+ background-color: rgba(64, 158, 255, 0.1);
960
1183
  }
961
1184
 
962
1185
  /* 选中行高亮 */
963
1186
  .row-selected {
964
- background-color: #ecf5ff !important;
1187
+ background-color: #ecf5ff !important;
965
1188
  }
966
1189
 
967
1190
  .gantt-row.row-selected td {
968
- background-color: #ecf5ff;
1191
+ background-color: #ecf5ff;
969
1192
  }
970
1193
  </style>