fileBar.vue 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. <template>
  2. <div class="file-chart">
  3. <div v-for="(item, index) in fileData" :key="index" class="item-container">
  4. <div class="file-label cursor-pointer" :class="{'active': activeIndex === index}" @click="toggleActive(index)">{{ item.name }}</div>
  5. <div class="file-bar">
  6. <div
  7. v-for="(value, subIndex) in item.data"
  8. :key="subIndex"
  9. class="bar-block"
  10. :style="{ width: computedWidths[index][subIndex] + 'px' }"
  11. >
  12. <div class="block-bg" :class="'bg-' + value.level">
  13. <el-tooltip
  14. class="tooltip-item"
  15. effect="light"
  16. :content="value.tag"
  17. placement="top"
  18. >
  19. <div class="cursor-pointer">{{ value.tag }}</div>
  20. </el-tooltip>
  21. </div>
  22. </div>
  23. </div>
  24. </div>
  25. <slot></slot>
  26. </div>
  27. </template>
  28. <script setup>
  29. import { onMounted, ref, computed } from "vue";
  30. const fileData = ref([
  31. {
  32. name: "高产级",
  33. data: [
  34. { value: 325, level: 4, tag: "325棵" },
  35. { value: 325, level: 3, tag: "325棵" },
  36. { value: 325, level: 2, tag: "325棵" },
  37. { value: 325, level: 1, tag: "325棵" },
  38. ],
  39. },
  40. {
  41. name: "稳产级",
  42. data: [
  43. { value: 260, level: 4, tag: "260棵" },
  44. { value: 270, level: 3, tag: "270棵" },
  45. { value: 270, level: 2, tag: "270棵" },
  46. { value: 270, level: 1, tag: "270棵" },
  47. ],
  48. },
  49. {
  50. name: "休养-幼树",
  51. data: [
  52. { value: 380, level: 0, tag: "已调养 <1年" },
  53. { value: 330, level: 0, tag: "已治愈 >1年" },
  54. { value: 200, level: 0, tag: "未治愈" },
  55. ],
  56. },
  57. {
  58. name: "休养-病虫",
  59. data: [
  60. { value: 380, level: 3, tag: "已治愈 <1年" },
  61. { value: 380, level: 1, tag: "已治愈 >1年" },
  62. { value: 140, level: 0, tag: "未治愈" },
  63. ],
  64. },
  65. {
  66. name: "休养-生长",
  67. data: [
  68. { value: 400, level: 2, tag: "已休养<1年" },
  69. { value: 380, level: 2, tag: "已休养1-2年" },
  70. { value: 420, level: 2, tag: "已休养>2年" },
  71. ],
  72. },
  73. ]);
  74. // 计算所有 data 中 value 属性的总和最大值
  75. const maxSum = computed(() => {
  76. return Math.max(
  77. ...fileData.value.map((item) =>
  78. item.data.reduce((sum, dataPoint) => sum + dataPoint.value, 0)
  79. )
  80. );
  81. });
  82. // 计算每个 dataPoint 的值在所有 data 中 value 总和最大值中所占的百分比
  83. const computedWidths = computed(() => {
  84. const max = maxSum.value;
  85. return fileData.value.map((item) => {
  86. // 258是右侧容器总宽度
  87. return item.data.map((dataPoint) =>
  88. ((dataPoint.value / max) * 230).toFixed(0)
  89. ); // 保留两位小数
  90. });
  91. });
  92. // 设置选中
  93. const activeIndex = ref(0)
  94. const toggleActive = (index) => {
  95. activeIndex.value = index
  96. }
  97. </script>
  98. <style lang="scss" scoped>
  99. .file-chart {
  100. padding: 0 6px;
  101. height: 100%;
  102. display: flex;
  103. flex-direction: column;
  104. align-items: center;
  105. justify-content: center;
  106. position: relative;
  107. &::after {
  108. content: "";
  109. position: absolute;
  110. top: 6px;
  111. left: 76px;
  112. width: 1px;
  113. height: calc(100% - 24px);
  114. background: rgba(255, 255, 255, 0.08);
  115. }
  116. .item-container {
  117. display: flex;
  118. width: 100%;
  119. color: #ffffff;
  120. margin-bottom: 12px;
  121. .file-label {
  122. width: 68px;
  123. text-align: center;
  124. font-size: 12px;
  125. padding: 0 4px;
  126. box-sizing: border-box;
  127. &.active {
  128. background: #2199F8;
  129. border-radius: 22px;
  130. }
  131. }
  132. .file-bar {
  133. width: calc(100% - 56px);
  134. display: flex;
  135. padding-left: 6px;
  136. height: 18px;
  137. font-size: 10px;
  138. div {
  139. white-space: nowrap;
  140. overflow: hidden;
  141. text-overflow: ellipsis;
  142. }
  143. .bar-block {
  144. text-align: center;
  145. border-radius: 0px 4px 4px 0px;
  146. padding: 1px;
  147. background-image: linear-gradient(
  148. to right,
  149. rgba(255, 223, 223, 0),
  150. rgba(234, 232, 232, 1)
  151. );
  152. .block-bg {
  153. padding-left: 2px;
  154. border-radius: 0px 4px 4px 0px;
  155. box-sizing: border-box;
  156. width: 100%;
  157. height: 100%;
  158. white-space: nowrap;
  159. overflow: hidden;
  160. text-overflow: ellipsis;
  161. }
  162. }
  163. .bg-0 {
  164. background-image: linear-gradient(to right, #042921, #0cba93);
  165. }
  166. .bg-1 {
  167. background: linear-gradient( 90deg, #2E2424 0%, #F86A01 100%);
  168. }
  169. .bg-2 {
  170. background: linear-gradient( 90deg, #2E2424 0%, #F29501 100%);
  171. }
  172. .bg-3 {
  173. background: linear-gradient( 90deg, #2E2424 0%, #E33C3C 100%);
  174. }
  175. .bg-4 {
  176. background: linear-gradient( 270deg, #665E55 0%, #232323 100%);
  177. }
  178. }
  179. }
  180. }
  181. </style>