581 lines
14 KiB
Vue
581 lines
14 KiB
Vue
<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 ? '环比' : '同比' }} {{ 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>
|