Files
geg-gas-web/src/views/erp/report/SalesAnalysis.vue

581 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div style="padding: 10px; box-sizing: border-box">
<div>
<div class="mumber-box">
<div class="mumber" v-for="(it, index) in data.Statistics" :key="index">
<div class="mum-left">
<img class="index-img" :src="'/src/assets/erp/index-icon' + (index + 1) + '.svg'" />
</div>
<div class="mum-right">
<div class="mum-title">{{ it.name }}万元</div>
<div class="mum">{{ it.num }}</div>
<div class="mum-than">
{{ index > 1 ? '环比' : '同比' }}&nbsp;&nbsp;&nbsp;&nbsp;{{ it.pecent }}%
<Icon
:icon="it.isUp ? 'ant-design:caret-up-outlined' : 'ant-design:caret-down-outlined'"
:color="it.isUp ? '#3dba84' : '#ee3b3b'"
:size="14"
class="icon"
/>
</div>
</div>
</div>
</div>
<a-row :gutter="10">
<a-col :span="6">
<div class="box-bg">
<div class="box-bg-title">
<span class="title-text">本月销售占比</span>
</div>
<div class="item" ref="homePieChart"></div>
</div>
</a-col>
<a-col :span="18">
<div class="box-bg">
<div class="box-bg-title">
<span class="title-text">销售分析</span>
</div>
<div class="item" ref="homeLineChart"></div>
</div>
</a-col>
<a-col :span="6">
<div class="box-bg">
<div class="box-bg-title">
<span class="title-text">本月收入占比</span>
</div>
<div class="item" ref="homePieChart2"></div>
</div>
</a-col>
<a-col :span="7">
<div class="box-bg" style="position: relative">
<div class="box-bg-title">
<span class="title-text">出库产品分析</span>
</div>
<div class="total">
<div>{{ data.total }}万元</div>
<div class="text">总出库产品金额</div>
</div>
<div class="item" ref="homeBar2Chart"></div>
</div>
</a-col>
<a-col :span="11">
<div class="box-bg">
<div class="box-bg-title">
<span class="title-text">本年利润偏差分析</span>
</div>
<div class="item" ref="homeBarChart"></div>
</div>
</a-col>
</a-row>
</div>
</div>
</template>
<script lang="ts" setup>
import { onMounted, nextTick, reactive, ref, unref, markRaw } from 'vue';
import {
getSaleDataInfo,
getProportionSaleInfo,
getSaleAnalysisInfo,
getProportionIncomeInfo,
getProductAnalysisInfo,
getProfitInfo,
} from '/@/api/erp/report/sales';
import Icon from '/@/components/Icon/index';
import * as echarts from 'echarts';
const formate = (name) => {
let str = name + '';
data.dataOne.forEach((o: any) => {
if (name == o.name) {
str += o.value + '万元';
}
});
return str;
};
const data = reactive({
colors: ['#5E95FF', '#00CACF', '#FF9100', '#995EFF', '#5E6EFF'],
Statistics: [] as any[],
dataOne: [],
// 玫瑰饼图
pieOption: {
color: ['#7EAAFF', '#5887E3', '#5E75E6', '#6D68F8', '#9E9BFC', '#8CB1F9'],
legend: {
orient: 'horizontal',
x: 'center',
y: 'bottom',
top: '78%',
itemWidth: 10,
itemHeight: 10,
itemGap: 20,
padding: [5, 5, 5, 5],
textStyle: {
color: '#85878e',
},
formatter: formate,
},
series: {
name: '',
center: ['50%', '32%'],
type: 'pie',
radius: [0, 85],
roseType: 'area',
itemStyle: {
borderRadius: 0,
},
label: {
color: '#6e7079',
overflow: 'none',
formatter: '{b}\n{d}%',
},
data: [],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)',
},
},
},
},
lineOption: {
color: ['#5E95FF', '#995EFF'],
title: {
text: '单位:%',
left: 20,
textStyle: {
color: '#333',
fontWeight: 'normal',
fontSize: 12,
},
},
legend: {
itemWidth: 20,
itemHeight: 10,
itemGap: 20,
right: 20,
textStyle: {
color: '#85878e',
},
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true,
},
xAxis: {
type: 'category',
boundaryGap: false,
data: [] as any[],
},
yAxis: {
type: 'value',
},
series: [] as any[],
},
// 占比饼图
pie2Option: {
color: ['#00FFE5', '#5E95FF', '#995EFF'],
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(51, 51, 51, 0.7)',
textStyle: {
color: '#fff',
},
formatter: '{b}<br/>{c}' + '万元<br/>' + '{d}%',
},
legend: {
bottom: '10%',
left: 'center',
itemWidth: 10,
itemHeight: 10,
itemGap: 20,
textStyle: {
color: '#85878e',
},
},
series: {
type: 'pie',
radius: ['40%', '60%'],
center: ['50%', '38%'],
avoidLabelOverlap: false,
labelLine: {
show: false,
},
data: [] as any[],
},
},
bar2Option: {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'none',
},
backgroundColor: 'rgba(51, 51, 51, 0.7)',
textStyle: {
color: '#fff',
},
formatter: '{b}<br/>{c}' + '万元',
},
grid: {
top: 90,
left: 20,
right: 30,
bottom: 20,
containLabel: true,
},
xAxis: {
data: [] as any[],
axisTick: {
show: false,
},
},
yAxis: {},
series: {
name: '',
type: 'pictorialBar',
showBackground: true,
backgroundStyle: {
color: 'rgba(221, 221, 221, 0.2)',
},
symbol: 'path://M0,10 L10,10 C5.5,10 5.5,5 5,0 C4.5,5 4.5,10 0,10 z',
itemStyle: {
opacity: 1,
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: '#5E95FF', // 0% 处的颜色
},
{
offset: 1,
color: '#695EFF', // 100% 处的颜色
},
],
global: false, // 缺省为 false
},
},
emphasis: {
itemStyle: {
opacity: 1,
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: '#FFF45E', // 0% 处的颜色
},
{
offset: 1,
color: '#FF9100', // 100% 处的颜色
},
],
global: false, // 缺省为 false
},
},
},
data: [] as any[],
z: 10,
},
},
total: 0,
barOption: {
color: ['#00CACF', '#5E95FF', '#FF9100'],
title: {
text: '单位:万元',
left: 20,
textStyle: {
color: '#333',
fontWeight: 'normal',
fontSize: 12,
},
},
grid: {
left: 20,
right: 30,
bottom: 20,
containLabel: true,
},
legend: {
itemWidth: 20,
itemHeight: 10,
itemGap: 20,
right: 20,
textStyle: {
color: '#85878e',
},
data: ['预计利润', '实际利润', '偏差率'],
},
xAxis: {
type: 'category',
data: [] as any[],
axisPointer: {
type: 'shadow',
},
},
yAxis: [
{
type: 'value',
name: '',
min: 0,
max: 0,
interval: 50,
},
{
type: 'value',
name: '',
axisLabel: {
formatter: '{value} %',
},
},
],
series: [] as any[],
},
});
const homePieChart = ref<HTMLDivElement>();
const homePieChart2 = ref<HTMLDivElement>();
const homeLineChart = ref<HTMLDivElement>();
const homeBar2Chart = ref<HTMLDivElement>();
const homeBarChart = ref<HTMLDivElement>();
onMounted(async () => {
let res = await getSaleDataInfo();
data.Statistics = res || [];
let res1 = await getProportionSaleInfo();
data.dataOne = res1 || [];
data.pieOption.series.data = data.dataOne;
let res2 = await getSaleAnalysisInfo();
data.lineOption.series = [];
data.lineOption.xAxis.data = [];
res2.forEach((o, i) => {
let arr: any[] = [];
o.data.forEach((k: any) => {
arr.push(k.value);
if (i == 1) data.lineOption.xAxis.data.push(k.name);
});
let obj = {
name: o.name,
type: 'line',
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: i === 0 ? '#5E95FF' : '#995EFF',
},
{
offset: 1,
color: '#fff',
},
]),
},
smooth: true,
data: arr,
};
data.lineOption.series.push(obj);
});
let res3 = await getProportionIncomeInfo();
res3.forEach((o) => {
let obj = {
name: o.name,
value: o.value,
label: {
show: false,
},
};
data.pie2Option.series.data.push(obj);
});
let res4 = await getProductAnalysisInfo();
res4.forEach((o) => {
data.bar2Option.xAxis.data.push(o.name);
data.bar2Option.series.data.push(o.value);
data.total += o.value;
});
let res5 = await getProfitInfo();
let total: any = [];
res5.forEach((o, i) => {
let arr: any[] = [];
o.data.forEach((k: any) => {
arr.push(k.value);
if (i == 1) data.barOption.xAxis.data.push(k.name);
});
let obj: any = {
name: o.name,
type: o.name == '偏差率' ? 'line' : 'bar',
data: arr,
};
if (o.name == '偏差率') {
obj.yAxisIndex = 1;
} else {
total = total.concat(arr);
}
data.barOption.series.push(obj);
});
data.barOption.yAxis[0].max = Math.max.apply(null, total);
nextTick(() => {
let myChart = markRaw(echarts.init(unref(homePieChart) as HTMLDivElement));
myChart.setOption(data.pieOption, true);
myChart.resize(); //显示区域大小发生改变更新图表
let myChart2 = markRaw(echarts.init(unref(homePieChart2) as HTMLDivElement));
myChart2.setOption(data.pie2Option, true);
myChart2.resize(); //显示区域大小发生改变更新图表
let myChart4 = markRaw(echarts.init(unref(homeLineChart) as HTMLDivElement));
myChart4.setOption(data.lineOption, true);
myChart4.resize(); //显示区域大小发生改变更新图表
let myChart5 = markRaw(echarts.init(unref(homeBar2Chart) as HTMLDivElement));
myChart5.setOption(data.bar2Option, true);
myChart5.resize(); //显示区域大小发生改变更新图表
let myChart6 = markRaw(echarts.init(unref(homeBarChart) as HTMLDivElement));
myChart6.setOption(data.barOption, true);
myChart6.resize(); //显示区域大小发生改变更新图表
});
});
</script>
<style lang="less" scoped>
.title-chose {
float: right;
margin-right: 20px;
span {
text-align: center;
padding: 0 12px;
display: inline-block;
color: #333;
height: 30px;
line-height: 30px;
font-size: 14px;
cursor: pointer;
margin-left: 10px;
&.cur,
&:active {
background-color: #5e95ff;
color: #fff;
}
}
}
.box-bg {
background-color: #fff;
box-sizing: border-box;
border-radius: 5px;
box-shadow: 0 3px 6px 1px rgb(0 0 0 / 10%);
.total {
margin: 20px 20px 0;
height: 46px;
padding: 0 10px;
position: absolute;
left: 0;
right: 0;
box-shadow: 0 3px 6px 1px rgb(0 0 0 / 16%);
display: flex;
justify-content: space-between;
font-size: 30px;
font-weight: 400;
align-items: center;
color: #5e95ff;
.text {
font-size: 18px;
font-weight: 400;
color: #707070;
}
}
.box-bg-title {
border-bottom: 1px solid #eee;
height: 50px;
line-height: 50px;
font-size: 16px;
box-sizing: border-box;
}
.title-text {
padding: 0 15px;
}
.item {
padding: 10px 10px 0;
height: 312px;
}
}
.mumber-box {
margin: 2px -5px 10px;
display: flex;
justify-content: space-between;
.mumber {
padding: 20px;
box-sizing: border-box;
margin: 0 5px;
flex: 1;
height: 120px;
background: #fff;
box-shadow: 0 3px 6px 1px rgb(0 0 0 / 10%);
border-radius: 5px;
.mum-left {
float: left;
width: 24%;
margin-top: 6px;
.index-img {
display: inline-block;
width: 100%;
}
}
.mum-right {
margin-left: 6%;
float: left;
width: 70%;
.mum-title {
font-size: 14px;
}
.mum {
font-size: 24px;
font-weight: bolder;
line-height: 40px;
color: #5e95ff;
}
.mum-than {
font-size: 14px;
.icon {
padding-left: 8px;
}
}
}
}
}
.ant-col {
margin-bottom: 10px;
}
</style>