| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- <template>
- <InfoCard title="成员职位情况分布">
- <div class="position-distribution">
- <div class="distribution-item">
- <div ref="skillChartRef" class="distribution-chart"></div>
- <div class="distribution-label">职业资格等级分布</div>
- </div>
- <div class="distribution-item">
- <div ref="operateChartRef" class="distribution-chart"></div>
- <div class="distribution-label">开机年限分布</div>
- </div>
- <div class="distribution-item">
- <div ref="postChartRef" class="distribution-chart"></div>
- <div class="distribution-label">岗位资质分布</div>
- </div>
- </div>
- </InfoCard>
- </template>
- <script setup>
- import { ref, onMounted, onUnmounted, nextTick, watch } from 'vue'
- import * as echarts from 'echarts'
- import InfoCard from './card.vue'
- const props = defineProps({
- chartData1: {
- type: Array,
- default: () => []
- },
- chartData2: {
- type: Array,
- default: () => []
- },
- chartData3: {
- type: Array,
- default: () => []
- }
- })
- const defaultSkillData = {
- categories: [],
- values: [],
- colors: ['#4da6ff', '#0f46fa']
- }
- const defaultOperateData = {
- categories: [],
- values: [],
- colors: ['#6bcb77', '#2ecc71']
- }
- const defaultPostData = {
- categories: [],
- values: [],
- colors: ['#ff6b6b', '#ee5a24']
- }
- const skillColors = ['#4da6ff', '#0f46fa']
- const operateColors = ['#6bcb77', '#2ecc71']
- const postColors = ['#ff6b6b', '#ee5a24']
- const skillChartRef = ref(null)
- let skillChart = null
- const operateChartRef = ref(null)
- let operateChart = null
- const postChartRef = ref(null)
- let postChart = null
- const transformData = (data, defaultData) => {
- if (!Array.isArray(data) || data.length === 0) {
- return {
- categories: defaultData.categories,
- values: defaultData.values,
- colors: defaultData.colors
- }
- }
- return {
- categories: data.map(item => item.name),
- values: data.map(item => item.value),
- colors: defaultData.colors
- }
- }
- const updateSkillChart = (data) => {
- if (!skillChartRef.value) return
- if (!skillChart) {
- skillChart = echarts.init(skillChartRef.value)
- }
- const chartData = transformData(data, defaultSkillData)
-
- skillChart.setOption({
- xAxis: {
- type: 'category',
- data: chartData.categories,
- axisLabel: { color: '#a0c4ff', fontSize: 10 },
- axisLine: { lineStyle: { color: 'rgba(15,70,250,0.3)' } }
- },
- yAxis: {
- type: 'value',
- axisLabel: { color: '#a0c4ff', fontSize: 10 },
- axisLine: { lineStyle: { color: 'rgba(15,70,250,0.3)' } },
- splitLine: { lineStyle: { color: 'rgba(15,70,250,0.2)' } }
- },
- series: [{
- type: 'bar',
- data: chartData.values,
- itemStyle: {
- color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
- { offset: 0, color: chartData.colors[0] },
- { offset: 1, color: chartData.colors[1] }
- ])
- },
- barWidth: '50%'
- }]
- })
- }
- const updateOperateChart = (data) => {
- if (!operateChartRef.value) return
- if (!operateChart) {
- operateChart = echarts.init(operateChartRef.value)
- }
- const chartData = transformData(data, defaultOperateData)
-
- operateChart.setOption({
- xAxis: {
- type: 'category',
- data: chartData.categories,
- axisLabel: { color: '#a0c4ff', fontSize: 10 },
- axisLine: { lineStyle: { color: 'rgba(15,70,250,0.3)' } }
- },
- yAxis: {
- type: 'value',
- axisLabel: { color: '#a0c4ff', fontSize: 10 },
- axisLine: { lineStyle: { color: 'rgba(15,70,250,0.3)' } },
- splitLine: { lineStyle: { color: 'rgba(15,70,250,0.2)' } }
- },
- series: [{
- type: 'bar',
- data: chartData.values,
- itemStyle: {
- color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
- { offset: 0, color: chartData.colors[0] },
- { offset: 1, color: chartData.colors[1] }
- ])
- },
- barWidth: '50%'
- }]
- })
- }
- const updatePostChart = (data) => {
- if (!postChartRef.value) return
- if (!postChart) {
- postChart = echarts.init(postChartRef.value)
- }
- const chartData = transformData(data, defaultPostData)
- postChart.setOption({
- xAxis: {
- type: 'category',
- data: chartData.categories,
- axisLabel: { color: '#a0c4ff', fontSize: 10 },
- axisLine: { lineStyle: { color: 'rgba(15,70,250,0.3)' } }
- },
- yAxis: {
- type: 'value',
- axisLabel: { color: '#a0c4ff', fontSize: 10 },
- axisLine: { lineStyle: { color: 'rgba(15,70,250,0.3)' } },
- splitLine: { lineStyle: { color: 'rgba(15,70,250,0.2)' } }
- },
- series: [{
- type: 'bar',
- data: chartData.values,
- itemStyle: {
- color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
- { offset: 0, color: chartData.colors[0] },
- { offset: 1, color: chartData.colors[1] }
- ])
- },
- barWidth: '50%'
- }]
- })
- }
- watch(() => props.chartData1, (val) => {
- updateSkillChart(val)
- }, { deep: true })
- watch(() => props.chartData2, (val) => {
- updateOperateChart(val)
- }, { deep: true })
- watch(() => props.chartData3, (val) => {
- updatePostChart(val)
- }, { deep: true })
- const initCharts = () => {
- updateSkillChart(props.chartData1)
- updateOperateChart(props.chartData2)
- updatePostChart(props.chartData3)
- }
- const handleResize = () => {
- if (skillChart) skillChart.resize()
- if (operateChart) operateChart.resize()
- if (postChart) postChart.resize()
- }
- onMounted(() => {
- nextTick(() => {
- setTimeout(() => {
- initCharts()
- window.addEventListener('resize', handleResize)
- }, 100)
- })
- })
- onUnmounted(() => {
- window.removeEventListener('resize', handleResize)
- if (skillChart) skillChart.dispose()
- if (operateChart) operateChart.dispose()
- if (postChart) postChart.dispose()
- })
- </script>
- <style lang="scss" scoped>
- .position-distribution {
- display: flex;
- justify-content: space-around;
- align-items: stretch;
- min-height: 280px;
- gap: 15px;
- padding: 10px 0;
- .distribution-item {
- flex: 1;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- min-width: 0;
- .distribution-chart {
- width: 100%;
- height: 200px;
- }
- .distribution-label {
- color: #a0c4ff;
- font-size: 12px;
- margin-top: 10px;
- text-align: center;
- }
- }
- }
- </style>
|