web/src/components/statistics/over/Revenue.vue

499 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 class="container">
<div class="revenue">
<Panel title="营收概况">
<template #tools>
<div class="time">
<div class="time_box"
v-for="(item,index) in dataSelector"
:key="index"
:class="{active:curDate?.name==item.name}"
@click="changeCheckDate(item)"
>
<span>{{ item.name }}</span>
</div>
<el-date-picker
v-model="selectDate"
type="daterange"
@change="changeDate"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
style="margin-left: 24px"
/>
</div>
</template>
<div class="revenue-content">
<div class="revenue-content-item">
<div class="revenue-content-item-text">
<div class="num">{{ data.totalRevenue || 0 }}<span class="unit">元</span></div>
<div class="name">营业收入</div>
<div class="text">日均:¥{{ (data.totalRevenue / averageNum).toFixed(2) || 0 }}</div>
</div>
<img class="image" src="/static/images/overView/1.png" alt="">
</div>
<div class="revenue-content-item">
<div class="revenue-content-item-text">
<div class="num">{{ data.totalOrderCount || 0 }}<span class="unit color1">人</span></div>
<div class="name color1">消费人次</div>
<div class="text">日均:{{ (data.totalOrderCount / averageNum).toFixed(0) || 0 }}</div>
</div>
<img class="image" src="/static/images/overView/2.png" alt="">
</div>
<div class="revenue-content-item">
<div class="revenue-content-item-text">
<div class="num">{{ data.socialRevenue || 0 }}<span class="unit color2">元</span></div>
<div class="name color2">医保收入</div>
<div class="text">日均:¥{{ (data.socialRevenue / averageNum).toFixed(2) || 0 }}</div>
<div class="text"><span>本金¥0.00&nbsp;&nbsp;赠金¥0.00</span></div>
</div>
<img class="image" src="/static/images/overView/3.png" alt="">
</div>
<div class="revenue-content-item">
<div class="revenue-content-item-text">
<div class="num">{{ data.socialOrderCount || 0 }}<span class="unit color3">人</span></div>
<div class="name color3">医保消费人次</div>
<div class="text">日均:{{ (data.socialOrderCount / averageNum).toFixed(0) || 0 }}</div>
</div>
<img class="image" src="/static/images/overView/4.png" alt="">
</div>
</div>
</Panel>
</div>
<div class="classification">
<div class="cost">
<Panel title="费用分类">
<div v-if="data.goodsTypeRevenue.length" ref="centerRef" class="center_item_content"
style="width: 100%;height: 100%"></div>
<el-empty v-else description="暂无数据"/>
</Panel>
</div>
<div class="payment">
<Panel title="支付分类">
<div v-if="data.payTypeRevenue.length" ref="centerItemRef" style="width: 100%;height: 100%">
</div>
<el-empty v-else description="暂无数据"/>
</Panel>
</div>
</div>
<div class="statistics-chart">
<div class="business-map">
<Panel title="营业收入趋势">
<div v-if="data.payTypeRevenue.length" ref="chartRef" style="width: 100%;height: 100%"></div>
<el-empty v-else description="暂无数据"/>
</Panel>
</div>
<div class="consumption-map">
<Panel title="消费人次趋势">
<div v-if="data.payTypeRevenue.length" ref="mainRef" style="width: 100%;height: 100%"></div>
<el-empty v-else description="暂无数据"/>
</Panel>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import {ref, onMounted} from 'vue'
import * as echarts from 'echarts';
import {post} from "@/utils/request.ts";
import Panel from "@/components/common/Panel.vue";
import {
getYesterday,
getToday,
getTomorrow,
getThisWeek,
getThisMonth,
formatDateArray,
getEndOfDay
} from "@/utils/dateUtils.ts"
const changeNum = ref(0)
const data = ref<any>({
goodsTypeRevenue: [0], // 商品类型收入
payTypeRevenue: [0], // 支付类型收入
totalOrderCount: 0, // 总订单数
totalRevenue: null, // 总收入
vipOrderCount: 0, // 患者订单数
vipRevenue: null // 患者收入
})
const beginTime = ref('')
const endTime = ref('')
const timeList = ref([])
const averageNum = ref(1)
const dataSelector = [
{name: '今天', func: getToday()},
{name: '昨天', func: getYesterday()},
{name: '本周', func: getThisWeek()},
{name: '本月', func: getThisMonth()},
]
const formatDate = (dateString: any) => {
const date = new Date(dateString);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始需要加1
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
};
// 创建 ref 引用
const centerRef = ref<HTMLElement | null>(null)
const centerItemRef = ref<HTMLElement | null>(null)
const chartRef = ref<HTMLElement | null>(null)
const mainRef = ref<HTMLElement | null>(null)
onMounted(() => {
initChart()
})
const getDateRange = () => {
let beginTime = ''
let endTime = ''
if (curDate.value == null) {
let dateArray = selectDate.value
beginTime = dateArray[0]
endTime = dateArray[1]
} else {
const date = curDate.value?.func
beginTime = date.start
endTime = date.end
}
if (beginTime==endTime){
endTime=getEndOfDay(endTime)
}
return {begin: beginTime, end: endTime}
}
const initChart = () => {
const date = getDateRange()
post('statistics/getRevenueOverview', {
beginTime: date.begin,
endTime: date.end
}).then((res: any) => {
data.value = res
// 初始化 ECharts 实例
if (data.value.goodsTypeRevenue.length) {
if (centerRef.value) {
const myChart = echarts.init(centerRef.value);
myChart.setOption(
{
tooltip: {
trigger: 'item'
},
legend: {
left: '80%',
orient: "vertical",
},
series: [
{
name: '费用分类',
type: 'pie',
radius: ['40%', '70%'],
avoidLabelOverlap: false,
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: false,
fontSize: 30,
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: [
{value: data.value.goodsTypeRevenue[0]?.totalRevenue, name: data.value.goodsTypeRevenue[0]?.name},
{value: data.value.goodsTypeRevenue[1]?.totalRevenue, name: data.value.goodsTypeRevenue[1]?.name},
{value: data.value.goodsTypeRevenue[2]?.totalRevenue, name: data.value.goodsTypeRevenue[2]?.name},
{value: data.value.goodsTypeRevenue[3]?.totalRevenue, name: data.value.goodsTypeRevenue[3]?.name},
]
}
]
}
)
}
}
if (data.value.payTypeRevenue.length) {
if (centerItemRef.value) {
const myChart = echarts.init(centerItemRef.value);
myChart.setOption(
{
tooltip: {
trigger: 'item'
},
legend: {
left: '80%',
orient: "vertical",
},
series: [
{
name: '支付方式',
type: 'pie',
radius: ['40%', '70%'],
avoidLabelOverlap: false,
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: false,
fontSize: 30,
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: [
{value: data.value.payTypeRevenue[0]?.totalRevenue, name: data.value.payTypeRevenue[0]?.name},
{value: data.value.payTypeRevenue[1]?.totalRevenue, name: data.value.payTypeRevenue[1]?.name},
{value: data.value.payTypeRevenue[2]?.totalRevenue, name: data.value.payTypeRevenue[2]?.name},
{value: data.value.payTypeRevenue[3]?.totalRevenue, name: data.value.payTypeRevenue[3]?.name},
{value: data.value.payTypeRevenue[4]?.totalRevenue, name: data.value.payTypeRevenue[4]?.name},
]
}
]
}
)
}
}
if (chartRef.value) {
const myChart = echarts.init(chartRef.value);
myChart.setOption(
{
title: {
text: ''
},
tooltip: {
trigger: 'axis'
},
legend: {
data: ['患者', '普通',]
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: true,
data: [
'2024-04-01',
'2024-03-30',
'2024-03-26',
'2024-03-22',
'2024-03-18',
'2024-03-14',
'2024-03-10',
'2024-03-06',
'2024-03-02',
]
},
yAxis: {
type: 'value'
},
series: [
{
name: '患者',
type: 'line',
stack: 'Total',
data: [120, 132, 101, 134, 90, 230, 210]
},
{
name: '普通',
type: 'line',
stack: 'Total',
data: [220, 182, 191, 234, 290, 330, 310]
}
]
}
);
}
if (mainRef.value) {
const myChart = echarts.init(mainRef.value);
myChart.setOption({
title: {
text: ''
},
tooltip: {},
xAxis: {
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
},
yAxis: {},
series: [
{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}
]
});
}
})
}
const disabledDate = (time: Date) => {
return time.getTime() > Date.now()
}
const selectDate = ref();
const curDate = ref<any>(dataSelector[0])
const changeDate = (date: any) => {
curDate.value = null
selectDate.value = formatDateArray(date)
initChart()
}
const changeCheckDate = (dateItem: any) => {
curDate.value = dateItem
selectDate.value = null
initChart()
}
</script>
<style scoped lang="scss">
.time {
display: flex;
align-items: center;
.time_box {
padding: 0 5px;
height: 30px;
border: 1px solid #d7d9da;
color: #000;
font-size: 15px;
display: flex;
align-items: center;
cursor: pointer;
&:hover {
color: #fff;
background: #409EFF;
}
}
}
.active{
color: #fff !important;
background: #409EFF;
}
.container {
display: flex;
flex-direction: column;
.revenue {
height: 276px;
background: #fff;
padding-bottom: 24px;
&-content {
height: 100%;
display: flex;
padding: 0 24px;
&-item {
flex: 1;
background: #F0F4FD;
margin-right: 8px;
border-radius: 30px;
display: flex;
justify-content: space-between;
&:nth-child(2) {
background: #E5F9FF;
}
&:nth-child(3) {
background: #FFF5EC;
}
&:last-child {
margin-right: 0;
background: #FFEEEE;
}
&-text {
margin: 18px 0 0 34px;
.num {
font-weight: bold;
font-size: 40px;
color: #333333;
font-style: normal;
.unit {
font-weight: bold;
font-size: 16px;
color: #4D6DE4;
font-style: normal;
}
}
.name {
font-weight: bold;
font-size: 18px;
color: #4D6DE4;
font-style: normal;
margin: 8px 0;
}
.text {
font-weight: 500;
font-size: 14px;
color: #999999;
font-style: normal;
margin-bottom: 8px;
}
}
.image {
width: 62px;
height: 58px;
margin: 48px 48px 0 0;
}
}
}
}
.classification {
height: 396px;
margin: 24px 0;
display: flex;
.cost {
flex: 1;
margin-right: 24px;
}
.payment {
flex: 1;
}
}
.statistics-chart {
height: 382px;
display: flex;
.business-map {
flex: 1;
margin-right: 24px;
}
.consumption-map {
flex: 1;
}
}
}
.color1 {
color: #26C8B1 !important;
}
.color2 {
color: #F69C51 !important;
}
.color3 {
color: #FF8686 !important;
}
</style>