ProcessPersonnelChart.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. <template>
  2. <div ref="chartRef" class="process-personnel-chart chart-container"></div>
  3. </template>
  4. <script>
  5. import * as echarts from 'echarts';
  6. export default {
  7. name: 'ProcessPersonnelChart',
  8. props: {
  9. data: {
  10. type: Array,
  11. default: () => []
  12. }
  13. },
  14. data() {
  15. return {
  16. chartInstance: null
  17. };
  18. },
  19. watch: {
  20. data: {
  21. handler() {
  22. this.updateChart();
  23. },
  24. deep: true
  25. }
  26. },
  27. mounted() {
  28. this.initChart();
  29. window.addEventListener('resize', this.handleResize);
  30. },
  31. beforeDestroy() {
  32. this.destroyChart();
  33. window.removeEventListener('resize', this.handleResize);
  34. },
  35. methods: {
  36. initChart() {
  37. const chartDom = this.$refs.chartRef;
  38. if (!chartDom) return;
  39. this.chartInstance = echarts.init(chartDom);
  40. this.updateChart();
  41. },
  42. updateChart() {
  43. if (!this.chartInstance || !this.data) return;
  44. const totalPersonnel = this.data.reduce((sum, item) => sum + item.value, 0);
  45. const option = {
  46. backgroundColor: 'transparent',
  47. tooltip: {
  48. trigger: 'item',
  49. formatter: '{b}:{c}人',
  50. textStyle: { color: '#000', whiteSpace: 'normal', fontSize: 14 },
  51. backgroundColor: '#fff',
  52. borderColor: '#2068b8',
  53. borderWidth: 1,
  54. padding: 10
  55. },
  56. legend: {
  57. type: 'scroll',
  58. orient: 'vertical',
  59. right: 20,
  60. top: 'center',
  61. bottom: 20,
  62. textStyle: { color: '#e9ecef', fontSize: 12, padding: [0, 8] },
  63. itemWidth: 12,
  64. itemHeight: 10,
  65. itemGap: 10,
  66. formatter: '{name}',
  67. align: 'left',
  68. scrollDataIndex: 0,
  69. pageButtonItemGap: 5,
  70. pageButtonPosition: 'end',
  71. pageFormatter: '{current}/{total}',
  72. pageIconColor: '#e9ecef',
  73. pageIconInactiveColor: '#6c757d',
  74. pageIconSize: [15, 15],
  75. pageTextStyle: { color: '#e9ecef', fontSize: 12 }
  76. },
  77. series: [{
  78. name: '在岗人数',
  79. type: 'pie',
  80. radius: ['45%', '80%'],
  81. center: ['30%', '50%'],
  82. avoidLabelOverlap: false,
  83. label: {
  84. show: true,
  85. position: 'center',
  86. formatter: `{total|${totalPersonnel}}\n{unit|在岗人员数(位)}`,
  87. textStyle: {
  88. textAlign: 'center',
  89. lineHeight: 22,
  90. rich: {
  91. total: { fontSize: 18, fontWeight: 'bold', color: '#fff' },
  92. unit: { fontSize: 8, color: '#ccc', marginTop: 5 }
  93. }
  94. }
  95. },
  96. data: this.data,
  97. color: [
  98. '#1163fb', '#14cdc9', '#f9bb19', '#712ed2', '#ec4899', '#06b6d4', '#6b7280',
  99. '#e74c3c', '#f39c12', '#f1c40f', '#2ecc71', '#3498db', '#9b59b6',
  100. '#e67e22', '#e91e63', '#c0392b', '#d35400', '#16a085', '#f4d03f',
  101. '#1abc9c', '#4caf50', '#2980b9', '#8e44ad', '#ad1457', '#512da8',
  102. '#ff5722', '#d84315', '#ff9800', '#f57c00', '#388e3c', '#03a9f4',
  103. '#0277bd', '#673ab7', '#ff1744', '#795548', '#607d8b', '#3f51b5'
  104. ]
  105. }]
  106. };
  107. this.chartInstance.setOption(option);
  108. },
  109. destroyChart() {
  110. if (this.chartInstance) {
  111. this.chartInstance.dispose();
  112. this.chartInstance = null;
  113. }
  114. },
  115. handleResize() {
  116. if (this.chartInstance) {
  117. this.chartInstance.resize();
  118. }
  119. }
  120. }
  121. };
  122. </script>
  123. <style scoped>
  124. .process-personnel-chart {
  125. width: 100%;
  126. height: 100%;
  127. }
  128. </style>