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

581 lines
14 KiB
Vue
Raw Normal View History

<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>