resume.vue 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. <template>
  2. <div class="chart-box">
  3. <div class="chart-item" v-for="(val, i) in list" :key="i">
  4. <Echarts :height="400" :option="val.option"></Echarts>
  5. </div>
  6. </div>
  7. </template>
  8. <script setup>
  9. defineOptions({ name: 'resume-analysis'})
  10. import { ref, onMounted, watch, nextTick } from 'vue'
  11. import cloneDeep from 'lodash/cloneDeep'
  12. import { getJobCvAgeCount, getJobCvEduCount, getJobCvSexCount, getJobCvExpCount } from '@/api/recruit/enterprise/statistics'
  13. const props = defineProps({
  14. query: Object
  15. })
  16. // 柱状图公共option
  17. const barCommonOption = {
  18. title: {
  19. text: ''
  20. },
  21. xAxis: {
  22. type: 'category',
  23. name: '范围',
  24. axisLabel: {
  25. rotate: 30
  26. },
  27. data: []
  28. },
  29. yAxis: {
  30. type: 'value',
  31. name: '数量(人)'
  32. },
  33. grid: {
  34. left: '20',
  35. top: '70',
  36. right: '50',
  37. bottom: '10',
  38. containLabel: true
  39. },
  40. series: [
  41. {
  42. data: [],
  43. type: 'bar',
  44. barWidth: 40,
  45. label: {
  46. show: true
  47. }
  48. }
  49. ]
  50. }
  51. const list = ref([
  52. {
  53. api: getJobCvSexCount,
  54. isPie: true,
  55. option: {
  56. title: {
  57. text: '性别分布'
  58. },
  59. tooltip: {
  60. trigger: 'item'
  61. },
  62. legend: {
  63. top: '5%',
  64. left: 'center'
  65. },
  66. series: [
  67. {
  68. name: '性别分布',
  69. type: 'pie',
  70. radius: ['40%', '70%'],
  71. avoidLabelOverlap: false,
  72. itemStyle: {
  73. borderRadius: 10,
  74. borderColor: '#fff',
  75. borderWidth: 2
  76. },
  77. label: {
  78. show: true,
  79. formatter: e => {
  80. return e.data.key + ': ' + e.value + '人'
  81. }
  82. },
  83. labelLine: {
  84. show: true
  85. },
  86. data: []
  87. }
  88. ]
  89. }
  90. },
  91. {
  92. api: getJobCvAgeCount,
  93. title: '年龄分布',
  94. option: cloneDeep(barCommonOption)
  95. },
  96. {
  97. api: getJobCvExpCount,
  98. title: '工作年限分布',
  99. option: cloneDeep(barCommonOption)
  100. },
  101. {
  102. api: getJobCvEduCount,
  103. title: '学历分布',
  104. option: cloneDeep(barCommonOption)
  105. }
  106. ])
  107. const getStatistics = () => {
  108. list.value.forEach(async (e) => {
  109. const data = await e.api(props.query)
  110. if (e.isPie) {
  111. e.option.series[0].data = data
  112. } else {
  113. e.option.title.text = e.title
  114. e.option.xAxis.data = data.x
  115. e.option.series[0].data = data.y
  116. }
  117. })
  118. }
  119. onMounted(() => {
  120. nextTick(() => {
  121. getStatistics()
  122. })
  123. })
  124. watch(
  125. () => props.query,
  126. (val) => {
  127. if (val) getStatistics()
  128. },
  129. { deep: true }
  130. )
  131. </script>
  132. <style scoped lang="scss">
  133. .chart-box {
  134. width: 100%;
  135. display: flex;
  136. flex-wrap: wrap;
  137. .chart-item {
  138. width: calc((100% - 12px) / 2);
  139. min-width: calc((100% - 12px) / 2);
  140. max-width: calc((100% - 12px) / 2);
  141. overflow: hidden;
  142. transition: all .2s linear;
  143. background-color: #f7f8fa;
  144. border-radius: 8px;
  145. margin: 0 12px 12px 0;
  146. padding: 12px;
  147. &:nth-child(2n) {
  148. margin-right: 0;
  149. }
  150. }
  151. }
  152. .fullChart {
  153. width: 100%;
  154. background-color: #f7f8fa;
  155. border-radius: 8px;
  156. padding: 12px;
  157. }
  158. </style>