admin/addon/cashier/source/os/pages/stat/index.vue

547 lines
15 KiB
Vue

<template>
<base-page>
<view class="common-wrap">
<view class="title">营业数据</view>
<view class="choice-day">
<view class="date-btn" :class="dateType == 'today' ? 'select' : ''" @click="switchDateType('today')" value="today">今日</view>
<view class="date-btn" :class="dateType == 'yesterday' ? 'select' : ''" @click="switchDateType('yesterday')" value="yesterday">昨日</view>
<view class="date-btn" :class="dateType == 'week' ? 'select' : ''" @click="switchDateType('week')" value="week">7日内</view>
<view class="date-btn" :class="dateType == 'month' ? 'select' : ''" @click="switchDateType('month')" value="month">30日内</view>
<view class="date-btn" :class="dateType == 'custom' ? 'select' : ''" @click="switchDateType('custom')" value="custom">自定义</view>
<view class="report text-color">
<text class="move iconfont iconicon-test"></text>
<text></text>
</view>
</view>
<view class="money" v-if="businessdata">
<view class="estimate" :class="statType == 'expected_earnings_total_money' ? 'estimate-active' : ''">
<view class="income">
<text class="income-name">预计收入()</text>
<!-- <uni-dropdown>
<view class="action" slot="dropdown-link"><i class="iconfont iconbangzhu js-prompt-top"></i></view>
<view slot="dropdown">
<view class="dropdown-content-box">
<view class="text">弹框展示内容</view>
<view class="arrow"></view>
</view>
</view>
</uni-dropdown> -->
</view>
<view class="num-money">
<text class="last_income">{{ businessdata.expected_earnings_total_money || 0.0 }}</text>
<text class="detail" @click="switchStatType('expected_earnings_total_money')">查看详情</text>
</view>
</view>
<view class="estimate" :class="statType == 'billing_money' ? 'estimate-active' : ''">
<view class="income">
<text class="income-name">开单金额数()</text>
<!-- <uni-dropdown>
<view class="action" slot="dropdown-link"><i class="iconfont iconbangzhu js-prompt-top"></i></view>
<view slot="dropdown">
<view class="dropdown-content-box">
<view class="text">弹框展示内容</view>
<view class="arrow"></view>
</view>
</view>
</uni-dropdown> -->
</view>
<view class="num-money">
<text class="last_income">{{ businessdata.billing_money || 0.0 }}</text>
<text class="detail" @click="switchStatType('billing_money')">查看详情</text>
</view>
</view>
<view class="estimate" :class="statType == 'billing_count' ? 'estimate-active' : ''">
<view class="income"><text class="income-name">开单数量</text></view>
<view class="num-money">
<text class="last_income">{{ businessdata.billing_count || 0 }}</text>
<text class="detail" @click="switchStatType('billing_count')">查看详情</text>
</view>
</view>
<view class="estimate" :class="statType == 'buycard_money' ? 'estimate-active' : ''">
<view class="income"><text class="income-name">办卡金额数()</text></view>
<view class="num-money">
<text class="last_income">{{ businessdata.buycard_money || 0.0 }}</text>
<text class="detail" @click="switchStatType('buycard_money')">查看详情</text>
</view>
</view>
<view class="estimate" :class="statType == 'buycard_count' ? 'estimate-active' : ''">
<view class="income"><text class="income-name">办卡数</text></view>
<view class="num-money">
<text class="last_income">{{ businessdata.buycard_count || 0 }}</text>
<text class="detail" @click="switchStatType('buycard_count')">查看详情</text>
</view>
</view>
<view class="estimate" :class="statType == 'recharge_money' ? 'estimate-active' : ''">
<view class="income"><text class="income-name">会员充值金额()</text></view>
<view class="num-money">
<text class="last_income">{{ businessdata.recharge_money || 0.0 }}</text>
<text class="detail" @click="switchStatType('recharge_money')">查看详情</text>
</view>
</view>
<view class="estimate" :class="statType == 'recharge_count' ? 'estimate-active' : ''">
<view class="income"><text class="income-name">会员充值数量</text></view>
<view class="num-money">
<text class="last_income">{{ businessdata.recharge_count || 0 }}</text>
<text class="detail" @click="switchStatType('recharge_count')">查看详情</text>
</view>
</view>
<view class="estimate" :class="statType == 'refund_money' ? 'estimate-active' : ''">
<view class="income"><text class="income-name">会员退款金额()</text></view>
<view class="num-money">
<text class="last_income">{{ businessdata.refund_money || 0.0 }}</text>
<text class="detail" @click="switchStatType('refund_money')">查看详情</text>
</view>
</view>
<view class="estimate" :class="statType == 'refund_count' ? 'estimate-active' : ''">
<view class="income"><text class="income-name">会员退款数量</text></view>
<view class="num-money">
<text class="last_income">{{ businessdata.refund_count || 0 }}</text>
<text class="detail" @click="switchStatType('refund_count')">查看详情</text>
</view>
</view>
<view class="estimate" :class="statType == 'order_member_count' ? 'estimate-active' : ''">
<view class="income"><text class="income-name">门店下单会员数</text></view>
<view class="num-money">
<text class="last_income">{{ businessdata.order_member_count || 0 }}</text>
<text class="detail" @click="switchStatType('order_member_count')">查看详情</text>
</view>
</view>
<view class="estimate" :class="statType == 'balance_money' ? 'estimate-active' : ''">
<view class="income"><text class="income-name">会员余额消费金额</text></view>
<view class="num-money">
<text class="last_income">{{ businessdata.balance_money || 0.0 }}</text>
<text class="detail" @click="switchStatType('balance_money')">查看详情</text>
</view>
</view>
</view>
</view>
<uni-popup ref="customTime">
<view class="pop-box">
<view class="pop-header">
<view class="pop-header-text">自定义时间选择</view>
<view class="pop-header-close" @click="$refs.customTime.close()"><i class="iconguanbi1 iconfont"></i></view>
</view>
<view class="pop-content ">
<uni-datetime-picker v-model="timeObj.custom" @change="changeTime" :end="endDate" :clearIcon="false" type="datetimerange" rangeSeparator="至" />
</view>
<view class="pop-bottom"><button class="primary-btn" @click="getStatData()">确定</button></view>
</view>
</uni-popup>
<uni-popup ref="chartsPop">
<view class="pop-box charts-pop">
<view class="pop-header">
<view class="pop-header-text">运营数据图表展示</view>
<view class="pop-header-close" @click="$refs.chartsPop.close()"><i class="iconguanbi1 iconfont"></i></view>
</view>
<view class="pop-content">
<qiun-data-charts type="line" :chartData="chartData" :eopts="{ seriesTemplate: { smooth: true } }" :ontouch="true" :opts="chartsOpts" />
</view>
<!-- <view class="pop-bottom"><button class="primary-btn" @click="getStatData()">确定</button></view> -->
</view>
</uni-popup>
</base-page>
</template>
<script>
export default {
data() {
return {
statType: 'expected_earnings_total_money',
statTypeArr: {
expected_earnings_total_money: '预计收入',
billing_money: '开单金额数',
billing_count: '开单数量',
buycard_money: '办卡金额数',
buycard_count: '办卡数',
recharge_money: '会员充值金额',
recharge_count: '会员充值数量',
refund_money: '会员退款金额',
refund_count: '会员退款数量',
order_member_count: '门店下单会员数',
balance_money: '会员余额消费金额'
},
dateType: 'today',
timeObj: {
today: [],
yesterday: [],
week: [],
month: [],
custom: []
},
chartData: {
categories: [],
series: []
},
businessdata: null,
chartsOpts: { enableScroll: true, xAxis: { scrollShow: true, itemCount: 24, disableGrid: true } }
};
},
onLoad() {
this.setDate();
this.getStatData();
},
onShow() {
let date = new Date();
var y = date.getFullYear();
var m = date.getMonth() + 1;
var d = date.getDate();
this.endDate = y + '-' + m + '-' + d + ' 23:59:59';
},
methods: {
// 重置图表数据
resetChartData() {
this.chartData.categories = [];
this.chartData.series = [];
},
setDate() {
let time = this.$util.timeTurnTimeStamp(this.$util.timeFormat(Date.now() / 1000, 'y-m-d'));
this.timeObj.today = [time, time + 86399];
this.timeObj.yesterday = [time - 86400, time - 1];
this.timeObj.week = [time - 604800, time];
this.timeObj.month = [time - 2592000, time];
},
switchDateType(type) {
this.dateType = type;
if (type == 'custom') {
this.$refs.customTime.open();
return false;
}
if (type == 'month') this.chartsOpts.xAxis.itemCount = 10;
else this.chartsOpts.xAxis.itemCount = 24;
this.getStatData();
},
switchStatType(type) {
this.statType = type;
this.$refs.chartsPop.open();
this.resetChartData();
this.getStatData();
setTimeout(() => {
this.getChartData();
}, 500);
},
changeTime(e) {
this.timeObj.custom = e;
this.chartsOpts.xAxis.itemCount = 10;
},
getStatData() {
if (this.dateType == 'custom') {
this.$refs.customTime.close();
this.timeObj.custom[0] = this.$util.timeTurnTimeStamp(this.timeObj.custom[0]) * 1000; // 解决自定义数据保存之后再次点击出现的数据错乱
this.timeObj.custom[1] = this.$util.timeTurnTimeStamp(this.timeObj.custom[1]) * 1000; // 解决自定义数据保存之后再次点击出现的数据错乱
}
this.getBusinessData();
},
getChartData() {
let url = '/cashier/storeapi/stat/dayStatData';
let data = {};
data.start_time = this.timeObj[this.dateType][0];
if (this.dateType == 'today' || this.dateType == 'yesterday') url = '/cashier/storeapi/stat/hourStatData';
else data.end_time = this.timeObj[this.dateType][1];
this.$api.sendRequest({
url: url,
data: data,
success: res => {
if (res.code >= 0) {
this.chartData.series = [];
this.chartData.series.push({
data: res.data[this.statType],
name: this.statTypeArr[this.statType]
});
this.chartData.categories = res.data.time;
}
}
});
},
getBusinessData() {
let data = {};
data.start_time = this.dateType == 'custom' ? parseInt(this.timeObj[this.dateType][0] / 1000) : parseInt(this.timeObj[this.dateType][0]);
data.end_time = this.dateType == 'custom' ? parseInt(this.timeObj[this.dateType][1] / 1000) : parseInt(this.timeObj[this.dateType][1]);
this.$api.sendRequest({
url: '/cashier/storeapi/stat/statTotal',
data: data,
success: res => {
if (res.code >= 0) {
this.businessdata = res.data;
}
}
});
}
}
};
</script>
<style>
.stat-input-inline .uni-date {
}
.pop-content >>> .uni-icons {
line-height: 0.32rem;
}
</style>
<style lang="scss" scoped>
.common-wrap {
padding: 0.2rem;
height: 100vh;
box-sizing: border-box;
}
.title {
display: flex;
margin-bottom: 0.21rem;
font-size: 0.16rem;
font-family: Source Han Sans CN;
font-weight: bold;
line-height: 0.2rem;
}
.choice-day {
display: flex;
}
.choice-time {
margin-top: 0.09rem;
font-size: 0.12rem;
font-family: Source Han Sans CN;
font-weight: 400;
line-height: 0.36rem;
}
.report {
display: flex;
justify-content: flex-end;
margin-right: 0.2rem;
font-size: 0.14rem;
font-family: Source Han Sans CN;
font-weight: 400;
line-height: 0.36rem;
cursor: pointer;
}
.move {
margin-right: 0.06rem;
}
.money {
display: flex;
flex-wrap: wrap;
margin-top: 0.35rem;
.estimate {
width: calc((100% - 0.85rem) / 5);
margin: 0 0.08rem 0.2rem;
padding: 0.2rem;
background: #fff;
border: 0.01rem solid #eee;
border-radius: 0.02rem;
cursor: pointer;
position: relative;
box-sizing: border-box;
.income {
display: flex;
flex-direction: row;
box-sizing: border-box;
line-height: 0.2rem;
.income-name {
font-size: 0.16rem;
}
}
.num-money {
.last_income {
display: block;
margin: 0.15rem 0;
font-size: 0.24rem;
font-weight: 500;
line-height: 0.2rem;
}
.detail {
display: block;
text-align: right;
color: $primary-color;
font-size: $uni-font-size-sm;
position: relative;
bottom: -0.05rem;
}
}
}
.estimate:last-child {
margin-right: 0;
}
}
.jantou {
margin-top: 0.05rem;
padding-left: 0.1rem;
height: 0.11rem;
}
.yesterday {
display: flex;
flex-wrap: wrap;
font-size: 0.12rem;
}
.top-num {
display: flex;
margin-left: 0.05rem;
font-size: 0.12rem;
font-weight: 400;
}
.date-btn {
height: 0.42rem;
line-height: 0.42rem;
font-size: 0.14rem;
padding: 0 0.3rem;
box-sizing: border-box;
border: 0.01rem solid #d2d2d2;
cursor: pointer;
border-right: none;
border-left: none;
position: relative;
}
.date-btn:nth-child(6)::after {
border-radius: 0 0.02rem 0.02rem 0;
}
.date-btn:first-child::after {
border-radius: 0.02rem 0 0 0.02rem;
}
.date-btn:first-child {
border-radius: 0.02rem 0 0 0.02rem;
}
.date-btn::after {
content: '';
position: absolute;
top: -0.01rem;
left: 0;
bottom: -0.01rem;
right: -0.01rem;
border-right: 0.01rem solid #d2d2d2;
border-left: 0.01rem solid #d2d2d2;
}
.select {
color: #fff;
background-color: $primary-color;
border-color: $primary-color;
}
.select::after {
z-index: 2;
border-color: $primary-color;
}
.select:first-child {
border-radius: 0.02rem 0 0 0.02rem;
}
.seleced:nth-child(6) {
border-radius: 0 0.02rem 0.02rem 0;
}
.c-datepicker-picker {
z-index: 99999999 !important;
}
.yesterday {
display: none;
}
.dropdown-content-box {
padding: 0.05rem 0;
margin-top: 0.05rem;
background-color: #fff;
border: 0.01rem solid #ebeef5;
border-radius: 0.04rem;
box-shadow: 0 0.01rem 0.12rem 0 rgba(0, 0, 0, 0.1);
position: relative;
.arrow {
position: absolute;
top: -0.06rem;
right: 0.06rem;
width: 0;
height: 0;
border-left: 0.06rem solid transparent;
border-right: 0.06rem solid transparent;
border-bottom: 0.06rem solid #fff;
}
.text {
display: flex;
align-items: center;
justify-content: center;
margin: 0;
padding: 0 0.1rem;
transition: all 0.3s;
font-size: 0.12rem;
width: 1.5rem;
box-sizing: border-box;
text-align: left;
line-height: 1.5;
}
}
.js-prompt-top {
color: #c8c9cc;
font-size: 0.14rem;
z-index: 999;
margin-left: 0.05rem;
cursor: pointer;
}
// pop弹框
.pop-box {
background: #ffffff;
width: 6rem;
height: 3.38rem;
.pop-header {
padding: 0 0.15rem 0 0.2rem;
height: 0.5rem;
line-height: 0.5rem;
border-bottom: 0.01rem solid #f0f0f0;
font-size: 0.14rem;
color: #333;
overflow: hidden;
border-radius: 0.02rem 0.2rem 0 0;
box-sizing: border-box;
display: flex;
justify-content: space-between;
.pop-header-text {
}
.pop-header-close {
cursor: pointer;
i {
font-size: 0.18rem;
}
}
}
.pop-content {
height: calc(100% - 1.05rem);
// overflow-y: scroll;
padding: 0.2rem;
box-sizing: border-box;
}
.pop-bottom {
padding: 0.1rem;
height: 0.65rem;
border-top: 0.01rem solid #eee;
button {
width: 95%;
}
}
}
.charts-pop {
width: 9.5rem;
height: 5.4rem;
background-color: #fff;
.pop-content {
width: 100%;
height: calc(100% - 1rem);
}
}
</style>