profile.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. <template>
  2. <div class="station-content-wrapper">
  3. <div class="station-content">
  4. <div class="content-row">
  5. <InfoCard title="团队成员">
  6. <RollingTable
  7. :columns="teamColumns"
  8. :data="teamData"
  9. />
  10. </InfoCard>
  11. <InfoCard title="成员基本情况分布">
  12. <div class="member-distribution">
  13. <div class="dist-item">
  14. <h4>性别分布</h4>
  15. <div ref="genderDistChartRef" class="dist-chart"></div>
  16. </div>
  17. <div class="dist-item">
  18. <h4>民族分布</h4>
  19. <div ref="nationDistChartRef" class="dist-chart"></div>
  20. </div>
  21. <div class="dist-item">
  22. <h4>政治面貌分布</h4>
  23. <div ref="politicalDistChartRef" class="dist-chart"></div>
  24. </div>
  25. </div>
  26. </InfoCard>
  27. </div>
  28. <div class="content-row" style="width: 50%;">
  29. <InfoCard title="成员职位情况分布">
  30. <div class="position-distribution">
  31. <div class="dist-item">
  32. <h4>职业资格等级分布</h4>
  33. <div ref="qualificationLevelChartRef" class="dist-chart"></div>
  34. </div>
  35. <div class="dist-item">
  36. <h4>开机年限分布</h4>
  37. <div ref="experienceYearsChartRef" class="dist-chart"></div>
  38. </div>
  39. <div class="dist-item">
  40. <h4>岗位资质分布</h4>
  41. <div ref="positionQualificationChartRef" class="dist-chart"></div>
  42. </div>
  43. </div>
  44. </InfoCard>
  45. </div>
  46. </div>
  47. </div>
  48. </template>
  49. <script setup>
  50. import { ref, onMounted, onUnmounted, nextTick } from 'vue'
  51. import * as echarts from 'echarts'
  52. import InfoCard from '../../components/card.vue'
  53. import RollingTable from '../../components/rollingTable.vue'
  54. const props = defineProps({
  55. queryParams: {
  56. type: Object,
  57. default: () => ({})
  58. }
  59. })
  60. const teamColumns = [
  61. { label: '部门', prop: 'dept' },
  62. { label: '员工数量', prop: 'empCount' },
  63. { label: '党员数量', prop: 'partyCount' },
  64. { label: '平均年龄', prop: 'avgAge' },
  65. { label: '平均工龄', prop: 'avgWorkYears' },
  66. { label: '职业资格证书等级', prop: 'certLevel' },
  67. { label: '平均升级年龄', prop: 'avgUpgradeAge' },
  68. { label: '综合得分', prop: 'totalScore' }
  69. ]
  70. const teamData = ref([
  71. { dept: '旅检一部', empCount: '800', partyCount: '7', avgAge: '25', avgWorkYears: '3', certLevel: '16', avgUpgradeAge: '3', totalScore: '90' },
  72. { dept: '旅检二部', empCount: '756', partyCount: '2', avgAge: '28', avgWorkYears: '8', certLevel: '18', avgUpgradeAge: '5', totalScore: '88' },
  73. { dept: '旅检三部', empCount: '708', partyCount: '7', avgAge: '25', avgWorkYears: '3', certLevel: '23', avgUpgradeAge: '3', totalScore: '86' }
  74. ])
  75. const genderDistChartRef = ref(null)
  76. let genderDistChart = null
  77. const nationDistChartRef = ref(null)
  78. let nationDistChart = null
  79. const politicalDistChartRef = ref(null)
  80. let politicalDistChart = null
  81. const qualificationLevelChartRef = ref(null)
  82. let qualificationLevelChart = null
  83. const experienceYearsChartRef = ref(null)
  84. let experienceYearsChart = null
  85. const positionQualificationChartRef = ref(null)
  86. let positionQualificationChart = null
  87. const initGenderDistChart = () => {
  88. if (!genderDistChartRef.value) return
  89. genderDistChart = echarts.init(genderDistChartRef.value)
  90. const option = {
  91. series: [{
  92. type: 'pie',
  93. radius: ['50%', '70%'],
  94. data: [
  95. { value: 650, name: '女', itemStyle: { color: '#ff9f9f' } },
  96. { value: 750, name: '男', itemStyle: { color: '#7effc4' } }
  97. ],
  98. label: { show: true, color: '#fff', fontSize: 11 },
  99. labelLine: { show: true }
  100. }]
  101. }
  102. genderDistChart.setOption(option)
  103. }
  104. const initNationDistChart = () => {
  105. if (!nationDistChartRef.value) return
  106. nationDistChart = echarts.init(nationDistChartRef.value)
  107. const option = {
  108. series: [{
  109. type: 'pie',
  110. radius: ['50%', '70%'],
  111. data: [
  112. { value: 615, name: '汉族', itemStyle: { color: '#7effc4' } },
  113. { value: 484, name: '回族', itemStyle: { color: '#4da6ff' } },
  114. { value: 156, name: '其他', itemStyle: { color: '#ffd93d' } }
  115. ],
  116. label: { show: true, color: '#fff', fontSize: 11 },
  117. labelLine: { show: true }
  118. }]
  119. }
  120. nationDistChart.setOption(option)
  121. }
  122. const initPoliticalDistChart = () => {
  123. if (!politicalDistChartRef.value) return
  124. politicalDistChart = echarts.init(politicalDistChartRef.value)
  125. const option = {
  126. series: [{
  127. type: 'pie',
  128. radius: ['50%', '70%'],
  129. data: [
  130. { value: 410, name: '群众', itemStyle: { color: '#ffd93d' } },
  131. { value: 540, name: '共青团员', itemStyle: { color: '#4da6ff' } },
  132. { value: 270, name: '中共党员', itemStyle: { color: '#ff6b6b' } },
  133. { value: 138, name: '预备党员', itemStyle: { color: '#7effc4' } }
  134. ],
  135. label: { show: true, color: '#fff', fontSize: 11 },
  136. labelLine: { show: true }
  137. }]
  138. }
  139. politicalDistChart.setOption(option)
  140. }
  141. const initQualificationLevelChart = () => {
  142. if (!qualificationLevelChartRef.value) return
  143. qualificationLevelChart = echarts.init(qualificationLevelChartRef.value)
  144. const option = {
  145. tooltip: {
  146. trigger: 'axis',
  147. backgroundColor: 'rgba(13,80,122,0.95)',
  148. borderColor: '#70CFE7',
  149. textStyle: { color: '#fff' }
  150. },
  151. legend: {
  152. data: ['人数'],
  153. textStyle: { color: '#a0c4ff' },
  154. top: 0
  155. },
  156. grid: {
  157. left: '10%',
  158. right: '10%',
  159. bottom: '15%',
  160. containLabel: true
  161. },
  162. xAxis: {
  163. type: 'category',
  164. data: ['等级1', '等级2', '等级3', '等级4', '等级5'],
  165. axisLabel: { color: '#a0c4ff', fontSize: 10 },
  166. axisLine: { lineStyle: { color: 'rgba(15,70,250,0.3)' } }
  167. },
  168. yAxis: {
  169. type: 'value',
  170. axisLabel: { color: '#a0c4ff' },
  171. axisLine: { lineStyle: { color: 'rgba(15,70,250,0.3)' } },
  172. splitLine: { lineStyle: { color: 'rgba(15,70,250,0.2)' } }
  173. },
  174. series: [{
  175. name: '人数',
  176. type: 'bar',
  177. data: [450, 650, 900, 750, 550],
  178. itemStyle: {
  179. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  180. { offset: 0, color: '#ff6b9d' },
  181. { offset: 1, color: '#ff6b6b' }
  182. ])
  183. },
  184. barWidth: '50%'
  185. }]
  186. }
  187. qualificationLevelChart.setOption(option)
  188. }
  189. const initExperienceYearsChart = () => {
  190. if (!experienceYearsChartRef.value) return
  191. experienceYearsChart = echarts.init(experienceYearsChartRef.value)
  192. const option = {
  193. tooltip: {
  194. trigger: 'axis',
  195. backgroundColor: 'rgba(13,80,122,0.95)',
  196. borderColor: '#70CFE7',
  197. textStyle: { color: '#fff' }
  198. },
  199. legend: {
  200. data: ['人数'],
  201. textStyle: { color: '#a0c4ff' },
  202. top: 0
  203. },
  204. grid: {
  205. left: '10%',
  206. right: '10%',
  207. bottom: '15%',
  208. containLabel: true
  209. },
  210. xAxis: {
  211. type: 'category',
  212. data: ['0-3', '4-7', '8-11', '12-15', '16-19'],
  213. axisLabel: { color: '#a0c4ff', fontSize: 10 },
  214. axisLine: { lineStyle: { color: 'rgba(15,70,250,0.3)' } }
  215. },
  216. yAxis: {
  217. type: 'value',
  218. axisLabel: { color: '#a0c4ff' },
  219. axisLine: { lineStyle: { color: 'rgba(15,70,250,0.3)' } },
  220. splitLine: { lineStyle: { color: 'rgba(15,70,250,0.2)' } }
  221. },
  222. series: [{
  223. name: '人数',
  224. type: 'bar',
  225. data: [650, 500, 400, 300, 550],
  226. itemStyle: {
  227. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  228. { offset: 0, color: '#a55eea' },
  229. { offset: 1, color: '#bd03fb' }
  230. ])
  231. },
  232. barWidth: '50%'
  233. }]
  234. }
  235. experienceYearsChart.setOption(option)
  236. }
  237. const initPositionQualificationChart = () => {
  238. if (!positionQualificationChartRef.value) return
  239. positionQualificationChart = echarts.init(positionQualificationChartRef.value)
  240. const option = {
  241. tooltip: {
  242. trigger: 'axis',
  243. backgroundColor: 'rgba(13,80,122,0.95)',
  244. borderColor: '#70CFE7',
  245. textStyle: { color: '#fff' }
  246. },
  247. legend: {
  248. data: ['人数'],
  249. textStyle: { color: '#a0c4ff' },
  250. top: 0
  251. },
  252. grid: {
  253. left: '10%',
  254. right: '10%',
  255. bottom: '15%',
  256. containLabel: true
  257. },
  258. xAxis: {
  259. type: 'category',
  260. data: ['仿伪', '炸探', '人身', '开包', '开检后', '开机'],
  261. axisLabel: { color: '#a0c4ff', fontSize: 10 },
  262. axisLine: { lineStyle: { color: 'rgba(15,70,250,0.3)' } }
  263. },
  264. yAxis: {
  265. type: 'value',
  266. axisLabel: { color: '#a0c4ff' },
  267. axisLine: { lineStyle: { color: 'rgba(15,70,250,0.3)' } },
  268. splitLine: { lineStyle: { color: 'rgba(15,70,250,0.2)' } }
  269. },
  270. series: [{
  271. name: '人数',
  272. type: 'bar',
  273. data: [450, 600, 180, 150, 650, 550],
  274. itemStyle: {
  275. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  276. { offset: 0, color: '#ffd93d' },
  277. { offset: 1, color: '#ffd9b3' }
  278. ])
  279. },
  280. barWidth: '50%'
  281. }]
  282. }
  283. positionQualificationChart.setOption(option)
  284. }
  285. const handleResize = () => {
  286. if (genderDistChart) genderDistChart.resize()
  287. if (nationDistChart) nationDistChart.resize()
  288. if (politicalDistChart) politicalDistChart.resize()
  289. if (qualificationLevelChart) qualificationLevelChart.resize()
  290. if (experienceYearsChart) experienceYearsChart.resize()
  291. if (positionQualificationChart) positionQualificationChart.resize()
  292. }
  293. onMounted(() => {
  294. nextTick(() => {
  295. setTimeout(() => {
  296. initGenderDistChart()
  297. initNationDistChart()
  298. initPoliticalDistChart()
  299. initQualificationLevelChart()
  300. initExperienceYearsChart()
  301. initPositionQualificationChart()
  302. window.addEventListener('resize', handleResize)
  303. }, 100)
  304. })
  305. })
  306. onUnmounted(() => {
  307. window.removeEventListener('resize', handleResize)
  308. if (genderDistChart) genderDistChart.dispose()
  309. if (nationDistChart) nationDistChart.dispose()
  310. if (politicalDistChart) politicalDistChart.dispose()
  311. if (qualificationLevelChart) qualificationLevelChart.dispose()
  312. if (experienceYearsChart) experienceYearsChart.dispose()
  313. if (positionQualificationChart) positionQualificationChart.dispose()
  314. })
  315. </script>
  316. <style lang="scss" scoped>
  317. .station-content-wrapper {
  318. .station-content {
  319. display: flex;
  320. flex-direction: column;
  321. gap: 20px;
  322. padding: 0 20px 40px;
  323. }
  324. .content-row {
  325. display: flex;
  326. gap: 20px;
  327. > .info-card {
  328. flex: 1;
  329. min-width: 0;
  330. }
  331. }
  332. .member-distribution,
  333. .position-distribution {
  334. display: flex;
  335. gap: 30px;
  336. justify-content: space-around;
  337. flex-wrap: wrap;
  338. .dist-item {
  339. flex: 1;
  340. min-width: 200px;
  341. text-align: center;
  342. h4 {
  343. color: #a0c4ff;
  344. margin-bottom: 15px;
  345. font-size: 16px;
  346. }
  347. .dist-chart {
  348. width: 100%;
  349. height: 200px;
  350. }
  351. }
  352. }
  353. .position-distribution {
  354. .dist-chart {
  355. height: 280px;
  356. }
  357. }
  358. }
  359. </style>