| | |
| | | method: 'get' |
| | | }) |
| | | } |
| | | |
| | | // 产品大类分布 |
| | | // /home/productCategoryDistribution |
| | | export const productCategoryDistribution = () => { |
| | | return request({ |
| | | url: '/home/productCategoryDistribution', |
| | | method: 'get' |
| | | }) |
| | | } |
| | |
| | | <Echarts |
| | | ref="chart" |
| | | :chartStyle="chartStyle" |
| | | :grid="grid" |
| | | :legend="workInProcessBarLegend" |
| | | :series="workInProcessBarSeries" |
| | | :tooltip="tooltip" |
| | | :xAxis="workInProcessXAxis" |
| | | :yAxis="workInProcessYAxis" |
| | | :legend="landLegend" |
| | | :series="landSeries" |
| | | :tooltip="landTooltip" |
| | | :color="landColors" |
| | | :options="{ backgroundColor: 'transparent', textStyle: { color: '#B8C8E0' } }" |
| | | style="height: 100%" |
| | | class="work-in-process-chart" |
| | | class="land-chart" |
| | | /> |
| | | </div> |
| | | </div> |
| | |
| | | import { ref, onMounted } from 'vue' |
| | | import Echarts from '@/components/Echarts/echarts.vue' |
| | | import PanelHeader from '../PanelHeader.vue' |
| | | import { getWorkInProcessTurnover } from '@/api/viewIndex.js' |
| | | import { productCategoryDistribution } from '@/api/viewIndex.js' |
| | | |
| | | // 在制品周转统计对象 |
| | | const workInProcessStatistics = ref({ |
| | | totalQuantity: 0, |
| | | avgTurnoverDays: 0, |
| | | turnoverEfficiency: 0, |
| | | }) |
| | | // 数据列表(来自接口) |
| | | const dataList = ref([]) |
| | | |
| | | // 在制品工序柱状图配置 |
| | | const workInProcessXAxis = ref([ |
| | | { |
| | | type: 'category', |
| | | axisTick: { show: false }, |
| | | axisLabel: { color: '#B8C8E0' }, |
| | | data: [], |
| | | }, |
| | | ]) |
| | | // 颜色列表 |
| | | const landColors = ['#26FFCB', '#24CBFF', '#35FBF4', '#2651FF', '#D1E4F5', '#5782F7', '#2F67EF', '#82BAFF'] |
| | | |
| | | const workInProcessYAxis = [ |
| | | { |
| | | type: 'value', |
| | | axisLabel: { color: '#B8C8E0' }, |
| | | name: '', |
| | | }, |
| | | ] |
| | | |
| | | const workInProcessBarLegend = { |
| | | // 图例配置(右侧竖排) |
| | | const landLegend = { |
| | | show: false, |
| | | textStyle: { color: '#B8C8E0' }, |
| | | icon: 'circle', |
| | | data: [], |
| | | right: '8%', |
| | | top: '40%', |
| | | orient: 'vertical', |
| | | itemGap: 14, |
| | | itemWidth: 6, |
| | | itemHeight: 6, |
| | | textStyle: { |
| | | fontSize: 12, |
| | | rich: { |
| | | unit: { |
| | | color: '#fff', |
| | | fontSize: 12, |
| | | padding: [0, 10, 0, 0], |
| | | }, |
| | | text: { |
| | | width: 60, |
| | | color: '#fff', |
| | | fontSize: 12, |
| | | }, |
| | | }, |
| | | }, |
| | | formatter: function (name) { |
| | | const list = dataList.value || [] |
| | | const item = list.find((d) => d.name === name) |
| | | if (!item) return name |
| | | const val = Number(item.value || 0) |
| | | const totalValue = list.reduce((sum, it) => sum + Number(it.value || 0), 0) |
| | | const percent = totalValue ? ((val / totalValue) * 100).toFixed(2) : '0.00' |
| | | return `{text|${name}}${val}{unit| 公顷}${percent}{unit|%}` |
| | | }, |
| | | } |
| | | |
| | | const workInProcessBarSeries = ref([ |
| | | // 提示框 |
| | | const landTooltip = { |
| | | triggerOn: 'click', |
| | | alwaysShowContent: true, |
| | | position: function (pt) { |
| | | return [pt[0], 130] |
| | | }, |
| | | } |
| | | |
| | | // 双层环形饼图 |
| | | const landSeries = ref([ |
| | | { |
| | | name: '在制品数量', |
| | | type: 'bar', |
| | | barWidth: 25, |
| | | barGap: 0, |
| | | emphasis: { |
| | | focus: 'series', |
| | | }, |
| | | itemStyle: { |
| | | color: { |
| | | type: 'linear', |
| | | x: 0, |
| | | y: 0, |
| | | x2: 0, |
| | | y2: 1, |
| | | colorStops: [ |
| | | { offset: 0, color: '#4EE4FF' }, |
| | | { offset: 1, color: '#00A4ED' }, |
| | | ], |
| | | }, |
| | | }, |
| | | name: '外圈', |
| | | type: 'pie', |
| | | radius: ['35%', '55%'], |
| | | center: ['50%', '50%'], |
| | | label: { |
| | | show: true, |
| | | position: 'top', |
| | | color: '#fff', |
| | | fontSize: 12, |
| | | lineHeight: 18, |
| | | formatter: function (params) { |
| | | const children = params?.data?.children || [] |
| | | if (!children.length) return '' |
| | | // label 展示 children 的 name + value |
| | | return children.map((c) => `${c.name} ${c.value}`).join('\n') |
| | | }, |
| | | }, |
| | | labelLine: { |
| | | show: true, |
| | | length: 40, |
| | | length2: 40, |
| | | lineStyle: { |
| | | color: '#B8C8E0', |
| | | }, |
| | | data: [], |
| | | }, |
| | | itemStyle: { |
| | | color: function (params) { |
| | | return landColors[params.dataIndex % landColors.length] |
| | | }, |
| | | }, |
| | | // 初始绑定为响应式数据源,后续通过接口填充 |
| | | data: dataList.value, |
| | | }, |
| | | { |
| | | // 内圈 |
| | | type: 'pie', |
| | | radius: ['35%', '40%'], |
| | | center: ['50%', '50%'], |
| | | silent: true, |
| | | label: { |
| | | show: false, |
| | | }, |
| | | labelLine: { |
| | | show: false, |
| | | }, |
| | | itemStyle: { |
| | | color: 'rgba(0, 127, 255, 0.25)', |
| | | }, |
| | | data: [1], |
| | | }, |
| | | ]) |
| | | |
| | | const chartStyle = { |
| | | width: '100%', |
| | | height: '115%', |
| | | height: '150%', |
| | | } |
| | | |
| | | const grid = { |
| | | left: '3%', |
| | | right: '4%', |
| | | bottom: '3%', |
| | | containLabel: true, |
| | | const loadData = async () => { |
| | | try { |
| | | const res = await productCategoryDistribution() |
| | | const items = res?.data?.items || [] |
| | | dataList.value = items.map((it) => ({ |
| | | name: it.name, |
| | | value: Number(it.value || 0), |
| | | rate: it.rate, |
| | | children: Array.isArray(it.children) ? it.children : [], |
| | | })) |
| | | landLegend.data = dataList.value.map((d) => d.name) |
| | | landSeries.value[0].data = dataList.value |
| | | } catch (e) { |
| | | console.error('获取产品大类分布失败:', e) |
| | | dataList.value = [] |
| | | landLegend.data = [] |
| | | landSeries.value[0].data = [] |
| | | } |
| | | |
| | | const tooltip = { |
| | | trigger: 'axis', |
| | | axisPointer: { |
| | | type: 'shadow', |
| | | }, |
| | | formatter: function (params) { |
| | | let result = params[0].axisValueLabel + '<br/>' |
| | | params.forEach((item) => { |
| | | result += `<div style="color: #B8C8E0">${item.marker} ${item.seriesName}: ${item.value}</div>` |
| | | }) |
| | | return result |
| | | }, |
| | | } |
| | | |
| | | // 在制品周转统计 |
| | | const workInProcessTurnoverInfo = () => { |
| | | getWorkInProcessTurnover() |
| | | .then((res) => { |
| | | console.log('在制品周转统计数据:', res) |
| | | |
| | | if (!res || !res.data) { |
| | | console.warn('在制品周转统计数据为空') |
| | | return |
| | | } |
| | | |
| | | // 从接口获取统计数据 |
| | | workInProcessStatistics.value = { |
| | | totalQuantity: res.data.totalOrderCount || 0, |
| | | avgTurnoverDays: res.data.averageTurnoverDays || 0, |
| | | turnoverEfficiency: res.data.turnoverEfficiency || 0, |
| | | } |
| | | |
| | | // 设置工序柱状图数据 |
| | | // X轴:processDetails (工序详情数组) |
| | | // Y轴:processQuantityDetails (工序数量详情数组) |
| | | if (res.data.processDetails && Array.isArray(res.data.processDetails)) { |
| | | // 设置X轴数据(工序名称) |
| | | workInProcessXAxis.value[0].data = res.data.processDetails |
| | | } else { |
| | | workInProcessXAxis.value[0].data = [] |
| | | } |
| | | |
| | | if ( |
| | | res.data.processQuantityDetails && |
| | | Array.isArray(res.data.processQuantityDetails) |
| | | ) { |
| | | // 设置Y轴数据(在制品数量) |
| | | workInProcessBarSeries.value[0].data = res.data.processQuantityDetails |
| | | } else { |
| | | workInProcessBarSeries.value[0].data = [] |
| | | } |
| | | }) |
| | | .catch((error) => { |
| | | console.error('获取在制品周转统计失败:', error) |
| | | }) |
| | | } |
| | | |
| | | onMounted(() => { |
| | | workInProcessTurnoverInfo() |
| | | loadData() |
| | | }) |
| | | </script> |
| | | |