2129 lines
63 KiB
Vue
2129 lines
63 KiB
Vue
<template>
|
||
<div class="app-container" style="padding-bottom: 100px">
|
||
<!-- <div class="card_wrap">
|
||
<div class="card">
|
||
<div class="header">
|
||
<div class="card_title">总销售额</div>
|
||
<el-tooltip effect="dark" content="订单支付金额" placement="top">
|
||
<i class="icon el-icon-warning-outline"></i>
|
||
</el-tooltip>
|
||
</div>
|
||
<div class="number">{{ topData.totalSales || 0 }}</div>
|
||
<div class="row">平均每单{{ topData.averageSales || 0 }}</div>
|
||
<div class="row">今日销售额{{ topData.totalSalesToday || 0 }}</div>
|
||
</div>
|
||
<div class="card">
|
||
<div class="header">
|
||
<div class="card_title">支付笔数</div>
|
||
</div>
|
||
<div class="number">{{ topData.paymentsNumber }}</div>
|
||
<div class="row" ref="cardPayChart" style="padding-bottom: 2px;"></div>
|
||
<div class="row">
|
||
今日支付笔数{{ topData.paymentsNumberToday || 0 }}
|
||
</div>
|
||
</div>
|
||
<div class="card">
|
||
<div class="header">
|
||
<div class="card_title">访问量</div>
|
||
</div>
|
||
<div class="number">{{ topData.totalVisits }}</div>
|
||
<div class="row" ref="cardCountChart" style="padding-bottom: 2px;"></div>
|
||
<div class="row">
|
||
<div class="dot"></div>
|
||
今日访问 {{ topData.totalVisitsToday || 0 }}
|
||
</div>
|
||
</div>
|
||
<div class="card">
|
||
<div class="header">
|
||
<div class="card_title">用户数</div>
|
||
</div>
|
||
<div class="number">{{ topData.totalUser }}</div>
|
||
<div class="row" ref="cardUserChart" style="padding-bottom: 2px;"></div>
|
||
<div class="row">
|
||
今日新增 {{ topData.userToday || 0 }}
|
||
<i class="icon el-icon-caret-top"></i>
|
||
</div>
|
||
</div>
|
||
</div> -->
|
||
<div class="h_card_wrap">
|
||
<div class="status_wrap">
|
||
<div class="left" style="flex-shrink: 0">
|
||
<div class="dot" />
|
||
<span>营业</span>
|
||
</div>
|
||
<div class="u-flex" style="flex-wrap: wrap">
|
||
<el-select v-if="isHeadShop == 1 && loginType == 0" v-model="shopId" placeholder="选择分店"
|
||
style="width: 200px; margin-right: 10px;" @change="shopChange">
|
||
<el-option v-for="item in branchList" :key="item.shopId" :label="item.shopName" :value="item.shopId" />
|
||
</el-select>
|
||
<div class="time_wrap u-flex" style="flex-shrink: 0">
|
||
<div class="date_list">
|
||
<div class="item" :class="{ active: dataListActive == index }" v-for="(item, index) in dateList"
|
||
:key="item.value" @click="timeChange(item.value, index)">
|
||
<!-- 标签文本 -->
|
||
<span class="date-tab-item">{{ item.label }}</span>
|
||
<!-- 分隔符:非最后一项才显示 -->
|
||
<span class="separator" v-if="index < dateList.length - 1">|</span>
|
||
</div>
|
||
</div>
|
||
<div class="u-flex">
|
||
<el-date-picker v-if="timeValue == 'custom'" v-model="query.createdAt" type="daterange"
|
||
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" value-format="YYYY-MM-DD"
|
||
@change="summarytrade" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div v-loading="tradeLoading" class="content">
|
||
<div class="top">
|
||
<div class="item earnings">
|
||
<div class="num_wrap">
|
||
<div class="num">{{ formatDecimal(trade.payAmount + trade.rechargeAmount || 0) }}</div>
|
||
<div class="tips">
|
||
营业额(元)
|
||
<el-tooltip popper-class="popper" effect="light" placement="bottom">
|
||
<template #content>
|
||
<div class="tips_row">
|
||
<div class="item">
|
||
<div class="left">
|
||
<img class="icon" src="@/assets/images/data/wx.png" />
|
||
<span>微信小程序</span>
|
||
</div>
|
||
<span class="num">{{ trade.wechatPayAmount || 0 }}</span>
|
||
</div>
|
||
<div class="item">
|
||
<div class="left">
|
||
<img class="icon" src="@/assets/images/data/ali.png" />
|
||
<span>支付宝小程序</span>
|
||
</div>
|
||
<span class="num">{{ trade.aliPayAmount || 0 }}</span>
|
||
</div>
|
||
<div class="item">
|
||
<div class="left">
|
||
<img class="icon" src="@/assets/images/data/scan.png" />
|
||
<span>主扫收款</span>
|
||
</div>
|
||
<span class="num">{{ trade.backScanPayAmount || 0 }}</span>
|
||
</div>
|
||
<div class="item">
|
||
<div class="left">
|
||
<img class="icon" src="@/assets/images/data/cash.png" />
|
||
<span>现金</span>
|
||
</div>
|
||
<span class="num">{{ trade.cashPayAmount || 0 }}</span>
|
||
</div>
|
||
<div class="item">
|
||
<div class="left">
|
||
<img class="icon" src="@/assets/images/data/cash.png" />
|
||
<span>充值</span>
|
||
</div>
|
||
<span class="num">{{ trade.rechargeAmount || 0 }}</span>
|
||
</div>
|
||
<div class="item">
|
||
<div class="left">
|
||
<img class="icon" src="@/assets/images/data/cash.png" />
|
||
<span>挂账</span>
|
||
</div>
|
||
<span class="num">{{ trade.creditPayAmount || 0 }}</span>
|
||
</div>
|
||
<div class="item">
|
||
<div class="left">
|
||
<img class="icon" src="@/assets/images/data/cash.png" />
|
||
<span>余额支付</span>
|
||
</div>
|
||
<span class="num">{{ trade.memberPayAmount || 0 }}</span>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
<el-icon>
|
||
<QuestionFilled />
|
||
</el-icon>
|
||
</el-tooltip>
|
||
</div>
|
||
</div>
|
||
<div class="line_wrap">
|
||
<div class="line_item">
|
||
<div class="line_item_top">
|
||
<div>销售金额(元)</div>
|
||
<!-- <div class="t">{{ formatDecimal(tradeSale.totalpayAmount || 0) }}</div> -->
|
||
</div>
|
||
<div class="line_gropress">
|
||
<div class="gropress l" :style="{
|
||
width: `${trade.payAmount
|
||
? (trade.payAmount / (trade.payAmount * 1 + trade.refundAmount * 1)) *
|
||
100
|
||
: 0
|
||
}%`,
|
||
}" />
|
||
<div class="gropress r" :style="{
|
||
width: `${trade.refundAmount
|
||
? (trade.refundAmount / (trade.payAmount * 1 + trade.refundAmount * 1)) *
|
||
100
|
||
: 0
|
||
}%`,
|
||
}" />
|
||
</div>
|
||
<div class="line_btm">
|
||
<el-icon class="icon el-icon-caret-right" />
|
||
<div class="info">
|
||
<span class="l_t">收:{{ formatDecimal(trade.payAmount || 0) }}</span>
|
||
<span class="l_r">退:{{ formatDecimal(trade.refundAmount || 0) }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="line_item">
|
||
<div class="line_item_top">
|
||
<div>充值金额(元)</div>
|
||
<!-- <div class="t">{{ formatDecimal(tradeSale.totalVipAmount || 0) }}</div> -->
|
||
</div>
|
||
<div class="line_gropress">
|
||
<div class="gropress l" :style="{
|
||
width: `${trade.rechargeAmount
|
||
? (trade.rechargeAmount /
|
||
(trade.memberPayAmount + trade.rechargeRefundAmount * 1)) *
|
||
100
|
||
: 0
|
||
}%`,
|
||
}" />
|
||
<div class="gropress r" :style="{
|
||
width: `${trade.rechargeRefundAmount
|
||
? (trade.rechargeRefundAmount /
|
||
(trade.memberPayAmount + trade.rechargeRefundAmount * 1)) *
|
||
100
|
||
: 0
|
||
}%`,
|
||
}" />
|
||
</div>
|
||
<div class="line_btm">
|
||
<el-icon class="icon el-icon-caret-right" />
|
||
<div class="info">
|
||
<span class="l_t">收:{{ formatDecimal(trade.rechargeAmount || 0) }}</span>
|
||
<span class="l_r">
|
||
退:{{ formatDecimal(trade.rechargeRefundAmount || 0) }}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="item data">
|
||
<div class="right_data_wrap">
|
||
<div class="item">
|
||
<div class="num">{{ formatDecimal(trade.memberPayAmount || 0) }}</div>
|
||
<div class="tips">余额支付金额(元)</div>
|
||
</div>
|
||
<div class="item">
|
||
<div class="num">{{ trade.memberPayCount || 0 }}</div>
|
||
<div class="tips">余额支付(笔)</div>
|
||
</div>
|
||
<div class="item">
|
||
<div class="num">{{ trade.newMemberCount || 0 }}</div>
|
||
<div class="tips">新增会员数(人)</div>
|
||
</div>
|
||
</div>
|
||
<!-- <div class="data_item">
|
||
<div class="num_wrap">
|
||
<div class="num">{{ formatDecimal(trade.memberPayAmount || 0) }}</div>
|
||
<div class="tips">会员消费(元)</div>
|
||
</div>
|
||
</div>
|
||
<div class="data_item_right">
|
||
<div class="t">
|
||
<span>新增会员数</span>
|
||
<span class="n">{{ trade.newMemberCount || 0 }}(人)</span>
|
||
</div>
|
||
<div class="t">
|
||
<span>会员消费笔数</span>
|
||
<span class="n">{{ trade.memberPayCount || 0 }}</span>
|
||
</div>
|
||
</div> -->
|
||
</div>
|
||
</div>
|
||
<div class="btm">
|
||
<div class="item item1">
|
||
<div class="title">
|
||
客单价
|
||
<el-tooltip effect="dark" :content="`订单实付金额(${trade.payAmount})/就餐人数(${trade.customerCount || 0})`"
|
||
placement="top">
|
||
<el-icon>
|
||
<QuestionFilled />
|
||
</el-icon>
|
||
</el-tooltip>
|
||
</div>
|
||
<div class="icon_wrap">
|
||
<img class="img" src="@/assets/images/data_home_item1_icon.png" />
|
||
<div class="t" style="color: #0080FF;">{{ formatDecimal(trade.avgPayAmount || 0) }}</div>
|
||
</div>
|
||
</div>
|
||
<div class="item item2">
|
||
<div class="title">
|
||
翻台率
|
||
<el-tooltip effect="dark"
|
||
:content="`翻台率=(客单数(${trade.customerCount || 0})-桌台数(${trade.tableCount || 0}))/桌台数*100%`"
|
||
placement="top">
|
||
<el-icon>
|
||
<QuestionFilled />
|
||
</el-icon>
|
||
</el-tooltip>
|
||
</div>
|
||
<div class="icon_wrap">
|
||
<img class="img" src="@/assets/images/data_home_item2_icon.png" />
|
||
<div class="t" style="color: #FFB200;">{{ trade.turnoverRate || 0 }}%</div>
|
||
</div>
|
||
</div>
|
||
<div class="item item3">
|
||
<div class="title">
|
||
优惠金额
|
||
<el-tooltip popper-class="popper" effect="light" placement="bottom">
|
||
<template #content>
|
||
<div class="tips_row">
|
||
<div class="item">
|
||
<div class="left">
|
||
<span>优惠类目</span>
|
||
</div>
|
||
<span class="num">优惠金额</span>
|
||
</div>
|
||
<div class="item">
|
||
<div class="left">
|
||
<span>新客立减</span>
|
||
</div>
|
||
<span class="num">{{ multiplyAndFormat(trade.newCustomerDiscountAmount || 0) }}</span>
|
||
</div>
|
||
<div class="item">
|
||
<div class="left">
|
||
<span>满减活动</span>
|
||
</div>
|
||
<span class="num">{{ multiplyAndFormat(trade.fullDiscountAmount || 0) }}</span>
|
||
</div>
|
||
<div class="item">
|
||
<div class="left">
|
||
<span>优惠券抵扣</span>
|
||
</div>
|
||
<span class="num">{{ multiplyAndFormat(trade.couponDiscountAmount || 0) }}</span>
|
||
</div>
|
||
<div class="item">
|
||
<div class="left">
|
||
<span>积分抵扣</span>
|
||
</div>
|
||
<span class="num">{{ multiplyAndFormat(trade.pointDiscountAmount || 0) }}</span>
|
||
</div>
|
||
<div class="item">
|
||
<div class="left">
|
||
<span>霸王餐</span>
|
||
</div>
|
||
<span class="num">{{ multiplyAndFormat(trade.backDiscountAmount || 0) }}</span>
|
||
</div>
|
||
<div class="item">
|
||
<div class="left">
|
||
<span>会员折扣</span>
|
||
</div>
|
||
<span class="num">{{ multiplyAndFormat(trade.memberDiscountAmount || 0) }}</span>
|
||
</div>
|
||
<div class="item">
|
||
<div class="left">
|
||
<span>订单改价</span>
|
||
</div>
|
||
<span class="num">{{ multiplyAndFormat(trade.orderPriceDiscountAmount || 0) }}</span>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
<el-icon>
|
||
<QuestionFilled />
|
||
</el-icon>
|
||
</el-tooltip>
|
||
</div>
|
||
<div class="icon_wrap">
|
||
<img class="img" src="@/assets/images/data_home_item3_icon.png" />
|
||
<div class="t" style="color: #FF8000;">{{ formatDecimal(trade.discountAmount || 0) }}</div>
|
||
</div>
|
||
</div>
|
||
<div class="item item4">
|
||
<div class="title">优惠笔数</div>
|
||
<div class="icon_wrap">
|
||
<img class="img" src="@/assets/images/data_home_item4_icon.png" />
|
||
<div class="t" style="color: #00CB71;">{{ trade.discountCount || 0 }}</div>
|
||
</div>
|
||
</div>
|
||
<div class="item item5">
|
||
<div class="row_wrap">
|
||
<div class="row">
|
||
<div class="title">毛利润</div>
|
||
<div class="icon_wrap">
|
||
<div class="t" style="color: #0000C2;">{{ trade.profitAmount || 0 }}</div>
|
||
</div>
|
||
</div>
|
||
<div class="row">
|
||
<div class="title">毛利率</div>
|
||
<div class="icon_wrap">
|
||
<div class="t" style="color: #0000C2;">{{ trade.profitRate || 0 }}%</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- <div class="item item6">
|
||
<div class="row_wrap">
|
||
<div class="row">
|
||
<div class="title">净利润</div>
|
||
<div class="icon_wrap">
|
||
<div class="t" style="color: #E30675;">{{ trade.netProfitAmount || 0 }}</div>
|
||
</div>
|
||
</div>
|
||
<div class="row">
|
||
<div class="title">净利率</div>
|
||
<div class="icon_wrap">
|
||
<div class="t" style="color: #E30675;">{{ trade.netProfitRate || 0 }}%</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div> -->
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- 销售额 -->
|
||
<div class="chart_wrap" style="display: flex">
|
||
<div class="item">
|
||
<div class="header">
|
||
<div class="tab_wrap">
|
||
<div class="item" :class="{ active: lineChartType == 0 }" @click="lineChartTypeChange(0)">
|
||
销售趋势
|
||
</div>
|
||
<div class="item" :class="{ active: lineChartType == 1 }" @click="lineChartTypeChange(1)">
|
||
支付占比
|
||
</div>
|
||
</div>
|
||
<el-radio-group v-model="saleActive" @change="lineChartTypeChange(lineChartType)">
|
||
<el-radio-button value="7">近7天</el-radio-button>
|
||
<el-radio-button value="30">30天</el-radio-button>
|
||
</el-radio-group>
|
||
</div>
|
||
<div v-show="lineChartType == 0" ref="saleChart" v-loading="saleLoading" class="chart" style="height: 350px" />
|
||
<div v-show="lineChartType == 1" ref="payChart" v-loading="payChartLoading" class="chart"
|
||
style="height: 350px" />
|
||
</div>
|
||
<!-- 商品销售排行 -->
|
||
<div class="item">
|
||
<div class="header">
|
||
<div class="tab_wrap">
|
||
<div class="item active">商品销售排行</div>
|
||
</div>
|
||
<el-radio-group v-model="saleTableActive" @change="rankChange">
|
||
<!-- <el-radio-button label="1">今天</el-radio-button> -->
|
||
<el-radio-button value="7">近7天</el-radio-button>
|
||
<el-radio-button value="30">30天</el-radio-button>
|
||
</el-radio-group>
|
||
</div>
|
||
<div class="sale_data">
|
||
<!-- <div class="card">
|
||
<div class="sale_data_header">
|
||
<div class="card_title">销售数量</div>
|
||
</div>
|
||
<div class="number">{{ productCount }}</div>
|
||
<div class="product_chart_wrap" ref="productCountChart"></div>
|
||
</div> -->
|
||
<!-- <div class="card">
|
||
<div class="sale_data_header">
|
||
<div class="card_title">销售金额</div>
|
||
</div>
|
||
<div class="number">¥{{ productSum }}</div>
|
||
<div class="product_chart_wrap" ref="productSumChart"></div>
|
||
</div> -->
|
||
</div>
|
||
<div class="table w-full">
|
||
<el-table v-loading="saleTableLoading" :data="saleTable" style="width: 100%">
|
||
<!-- <el-table-column label="排名" prop="productId"></el-table-column> -->
|
||
<el-table-column label="商品名称" prop="productName" />
|
||
<el-table-column label="数量" prop="saleCount" />
|
||
<el-table-column label="金额" prop="saleAmount" />
|
||
</el-table>
|
||
<!-- <div class="head-container" style="padding-top: 20px; display: flex; justify-content: flex-end">
|
||
<el-pagination :total="saleTableTotal" :page-size="saleTableSize" :current-page="saleTablePage"
|
||
layout="total, prev, pager, next, jumper" @current-change="paginationChange" />
|
||
</div> -->
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="chart_wrap">
|
||
<!-- 毛利率/净利率 -->
|
||
<div class="item">
|
||
<div class="header">
|
||
<div class="rate_title">
|
||
<div class="column">
|
||
<span class="t1">毛利率</span>
|
||
<span class="t2">今天 {{ initInterestRateTime }} 更新</span>
|
||
</div>
|
||
<!-- <span class="t1">毛利率/净利率</span> -->
|
||
<el-radio-group v-model="interestRateDay" @change="profitRateBarChart">
|
||
<el-radio-button value="7">近7天</el-radio-button>
|
||
<el-radio-button value="30">30天</el-radio-button>
|
||
</el-radio-group>
|
||
</div>
|
||
</div>
|
||
<div ref="initInterestRate" v-loading="initInterestRateLoading" class="chart" style="height: 350px" />
|
||
</div>
|
||
<!-- 成本(元) -->
|
||
<div class="item">
|
||
<div class="header">
|
||
<div class="rate_title">
|
||
<div class="column">
|
||
<span class="t1">成本(元)</span>
|
||
<span class="t2">今天 {{ costUpdateTime }} 更新</span>
|
||
</div>
|
||
<el-radio-group v-model="costDay" @change="costLineChart">
|
||
<el-radio-button value="7">近7天</el-radio-button>
|
||
<el-radio-button value="30">30天</el-radio-button>
|
||
</el-radio-group>
|
||
</div>
|
||
</div>
|
||
<div ref="costRef" v-loading="costLoading" class="chart" style="height: 350px" />
|
||
</div>
|
||
</div>
|
||
<!-- <div class="chart_wrap" style="display: flex;">
|
||
<div class="item" style="margin-left: 20px;">
|
||
<div class="header">
|
||
<div class="tab_wrap">
|
||
<div class="item active">支付占比类型</div>
|
||
</div>
|
||
<el-radio-group v-model="payChartDay" @change="datePayType">
|
||
<el-radio-button label="7">近7天</el-radio-button>
|
||
<el-radio-button label="30">30天</el-radio-button>
|
||
</el-radio-group>
|
||
</div>
|
||
<div style="height: 400px;margin-top: 30px;" ref="payChart" v-loading="payChartLoading"></div>
|
||
</div>
|
||
</div> -->
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import dataSummaryApi from "@/api/order/data-summary";
|
||
import ShopApi from "@/api/account/shop";
|
||
import dayjs from "dayjs";
|
||
import * as echarts from "echarts";
|
||
import { debounce, formatDecimal } from "@/utils/tools";
|
||
import { formatDateRange } from './utils/index.js'
|
||
import { multiplyAndFormat } from '@/utils/index.js'
|
||
export default {
|
||
name: "home",
|
||
data() {
|
||
return {
|
||
multiplyAndFormat,
|
||
dataListActive: 0,
|
||
dateList: [
|
||
{
|
||
label: "今天",
|
||
value: "today",
|
||
},
|
||
{
|
||
label: "昨天",
|
||
value: "yesterday",
|
||
},
|
||
{
|
||
label: "最近7天",
|
||
value: "last_7_days",
|
||
},
|
||
{
|
||
label: "最近30天",
|
||
value: "last_30_days",
|
||
},
|
||
{
|
||
label: "本周",
|
||
value: "this_week",
|
||
},
|
||
{
|
||
label: "本月",
|
||
value: "this_month",
|
||
},
|
||
{
|
||
label: "自定义",
|
||
value: "custom",
|
||
},
|
||
],
|
||
payCount: [
|
||
{
|
||
icon: "https://cashier-oss.oss-cn-beijing.aliyuncs.com/static/wx.png",
|
||
isAmount: "1",
|
||
payAmount: 0,
|
||
payType: "微信小程序",
|
||
saveAmount: null,
|
||
},
|
||
{
|
||
icon: "https://cashier-oss.oss-cn-beijing.aliyuncs.com/static/ali.png",
|
||
isAmount: "1",
|
||
payAmount: 0,
|
||
payType: "支付宝小程序",
|
||
saveAmount: null,
|
||
},
|
||
{
|
||
icon: "https://cashier-oss.oss-cn-beijing.aliyuncs.com/static/scan.png",
|
||
isAmount: "1",
|
||
payAmount: 0,
|
||
payType: "主扫收款",
|
||
saveAmount: null,
|
||
},
|
||
{
|
||
icon: "https://cashier-oss.oss-cn-beijing.aliyuncs.com/static/bscan.png",
|
||
isAmount: "1",
|
||
payAmount: 0,
|
||
payType: "收款码收款",
|
||
saveAmount: null,
|
||
},
|
||
{
|
||
icon: "https://cashier-oss.oss-cn-beijing.aliyuncs.com/static/cash.png",
|
||
isAmount: "1",
|
||
payAmount: 0,
|
||
payType: "现金",
|
||
saveAmount: null,
|
||
},
|
||
{
|
||
icon: "https://cashier-oss.oss-cn-beijing.aliyuncs.com/static/vipIn.png",
|
||
isAmount: "1",
|
||
payAmount: 0,
|
||
payType: "充值",
|
||
saveAmount: null,
|
||
},
|
||
],
|
||
branchList: [],
|
||
shopId: null,
|
||
trade: {},
|
||
formatDecimal,
|
||
topData: "",
|
||
saleTab: "sale",
|
||
saleActive: "7",
|
||
cardPayChart: null,
|
||
cardCountChart: null,
|
||
cardUserChart: null,
|
||
saleLoading: false,
|
||
saleChart: null,
|
||
payChartDay: "7",
|
||
payChartLoading: false,
|
||
payChart: null,
|
||
chartType: 1,
|
||
productCount: 0,
|
||
productSum: 0,
|
||
saleTableActive: "7",
|
||
saleTable: [],
|
||
saleTableLoading: false,
|
||
saleTablePage: 1,
|
||
saleTableTotal: 0,
|
||
saleTableSize: 5,
|
||
__resizeHandler: null,
|
||
productCountChart: null,
|
||
productSumChart: null,
|
||
lineChartType: 0,
|
||
timeValue: "today",
|
||
query: {
|
||
createdAt: [dayjs().format("YYYY-MM-DD"), dayjs().format("YYYY-MM-DD")],
|
||
},
|
||
tradeLoading: false,
|
||
tradeSale: {
|
||
payCount: [],
|
||
},
|
||
tradeVip: "",
|
||
tradeCount: "",
|
||
isHeadShop: JSON.parse(localStorage.getItem("userInfo")).isHeadShop,
|
||
loginType: localStorage.getItem("loginType"),
|
||
shopInfo: JSON.parse(localStorage.getItem("userInfo")),
|
||
initInterestRateLoading: true,
|
||
initInterestRate: null,
|
||
initInterestRateTime: '',
|
||
costLoading: true,
|
||
costRef: null,
|
||
costUpdateTime: '',
|
||
interestRateDay: '7',
|
||
costDay: '7'
|
||
};
|
||
},
|
||
computed: {
|
||
yingyeShiShou() {
|
||
if (!this.trade) {
|
||
return 0;
|
||
}
|
||
return (
|
||
this.trade.wechatPayAmount * 1 +
|
||
this.trade.aliPayAmount * 1 +
|
||
this.trade.aliPayAmount * 1 +
|
||
this.trade.memberPayAmount * 1 +
|
||
this.trade.scanPayAmount * 1 +
|
||
this.trade.cashPayAmount * 1 +
|
||
this.trade.rechargeAmount * 1
|
||
);
|
||
},
|
||
},
|
||
mounted() {
|
||
let shopInfo = JSON.parse(localStorage.getItem('userInfo'))
|
||
if (shopInfo.isHeadShop) {
|
||
this.shopId = shopInfo.id
|
||
} else {
|
||
this.shopId = localStorage.getItem('shopId')
|
||
}
|
||
|
||
// 增加首页提示是否账号30天过期
|
||
let date = dayjs(localStorage.getItem("expireDate")).diff(dayjs().format("YYYY-MM-DD"), "day");
|
||
if (date <= 30 && date >= 0) {
|
||
this.$alert(
|
||
`店铺账号有限期至${localStorage.getItem("expireDate")},店铺账号到期剩余${date}天!`,
|
||
"提示"
|
||
);
|
||
}
|
||
// this.summaryGet();
|
||
this.dateAmount();
|
||
this.dateProduct();
|
||
// this.summaryDateGet();
|
||
this.timeChange(this.timeValue);
|
||
this.profitRateBarChart()
|
||
this.costLineChart()
|
||
|
||
this.__resizeHandler = debounce(() => {
|
||
if (this.saleChart) {
|
||
this.saleChart.resize();
|
||
}
|
||
if (this.payChart) {
|
||
this.payChart.resize();
|
||
}
|
||
if (this.cardPayChart) {
|
||
this.cardPayChart.resize();
|
||
}
|
||
if (this.cardUserChart) {
|
||
this.cardUserChart.resize();
|
||
}
|
||
if (this.productCountChart) {
|
||
this.productCountChart.resize();
|
||
}
|
||
if (this.initInterestRate) {
|
||
this.initInterestRate.resize();
|
||
}
|
||
if (this.costRef) {
|
||
this.costRef.resize();
|
||
}
|
||
// if (this.productSumChart) {
|
||
// this.productSumChart.resize();
|
||
// }
|
||
}, 100);
|
||
window.addEventListener("resize", this.__resizeHandler);
|
||
this.geiShopList()
|
||
// this.initCardUserChart();
|
||
},
|
||
methods: {
|
||
/**
|
||
* 获取分店列表
|
||
*/
|
||
async geiShopList() {
|
||
try {
|
||
let shopInfo = JSON.parse(localStorage.getItem('userInfo'))
|
||
if (shopInfo.isHeadShop) {
|
||
let res = await ShopApi.getBranchList()
|
||
this.branchList = res;
|
||
this.shopId = res[0].shopId
|
||
}
|
||
} catch (error) {
|
||
console.log('获取分店列表===', error);
|
||
}
|
||
},
|
||
shopChange() {
|
||
this.summarytrade();
|
||
this.lineChartTypeChange(this.lineChartType)
|
||
this.dateProduct()
|
||
|
||
this.profitRateBarChart()
|
||
this.costLineChart()
|
||
},
|
||
// 切换时间
|
||
timeChange(e, index = 0) {
|
||
this.dataListActive = index;
|
||
this.timeValue = e;
|
||
this.query.createdAt = formatDateRange(e)
|
||
if (e != "custom") {
|
||
this.summarytrade();
|
||
}
|
||
},
|
||
// 获取营业板块数据
|
||
async summarytrade() {
|
||
try {
|
||
this.tradeLoading = true;
|
||
// if( this.query.createdAt[1] ){
|
||
// this.query.createdAt.splice(1,1,this.query.createdAt[1].replace("00:00:00","23:59:59"))
|
||
// }
|
||
const res = await dataSummaryApi.trade({
|
||
beginDate: this.query.createdAt[0],
|
||
endDate: this.query.createdAt[1],
|
||
rangeType: this.timeValue,
|
||
shopId: this.shopId
|
||
});
|
||
this.trade = res;
|
||
this.tradeSale = res.sale;
|
||
this.tradeVip = res.vip;
|
||
this.tradeCount = res.count;
|
||
} catch (error) {
|
||
console.log(error);
|
||
}
|
||
setTimeout(() => {
|
||
this.tradeLoading = false;
|
||
}, 500);
|
||
},
|
||
lineChartTypeChange(i) {
|
||
this.lineChartType = i;
|
||
if (i == 0) {
|
||
this.dateAmount();
|
||
} else {
|
||
this.datePayType();
|
||
}
|
||
},
|
||
// 初始化支付笔数柱状图
|
||
initCardPayChart(time = [], data = []) {
|
||
this.cardPayChart = echarts.init(this.$refs.cardPayChart);
|
||
this.cardPayChart.setOption({
|
||
tooltip: {
|
||
trigger: "axis",
|
||
},
|
||
grid: {
|
||
x: 0,
|
||
y: 0,
|
||
x2: 0,
|
||
y2: 0,
|
||
},
|
||
xAxis: [
|
||
{
|
||
type: "category",
|
||
data: time,
|
||
show: false, // 不显示坐标轴线、坐标轴刻度线和坐标轴上的文字
|
||
axisTick: {
|
||
show: false, // 不显示坐标轴刻度线
|
||
},
|
||
axisLine: {
|
||
show: false, // 不显示坐标轴线
|
||
},
|
||
axisLabel: {
|
||
show: false, // 不显示坐标轴上的文字
|
||
},
|
||
splitLine: {
|
||
show: false, // 不显示网格线
|
||
},
|
||
},
|
||
],
|
||
color: "#409eff",
|
||
yAxis: [
|
||
{
|
||
type: "value",
|
||
show: false, // 不显示坐标轴线、坐标轴刻度线和坐标轴上的文字
|
||
axisTick: {
|
||
show: false, // 不显示坐标轴刻度线
|
||
},
|
||
axisLine: {
|
||
show: false, // 不显示坐标轴线
|
||
},
|
||
axisLabel: {
|
||
show: false, // 不显示坐标轴上的文字
|
||
},
|
||
splitLine: {
|
||
show: false, // 不显示网格线
|
||
},
|
||
},
|
||
],
|
||
series: [
|
||
{
|
||
data: data,
|
||
type: "bar",
|
||
barWidth: "30%",
|
||
},
|
||
],
|
||
});
|
||
},
|
||
// 初始化访问量柱状图
|
||
initCardCountChart(time = [], data = []) {
|
||
this.cardCountChart = echarts.init(this.$refs.cardCountChart);
|
||
this.cardCountChart.setOption({
|
||
tooltip: {
|
||
trigger: "axis",
|
||
},
|
||
grid: {
|
||
x: 0,
|
||
y: 0,
|
||
x2: 0,
|
||
y2: 0,
|
||
},
|
||
xAxis: [
|
||
{
|
||
type: "category",
|
||
data: time,
|
||
show: false, // 不显示坐标轴线、坐标轴刻度线和坐标轴上的文字
|
||
axisTick: {
|
||
show: false, // 不显示坐标轴刻度线
|
||
},
|
||
axisLine: {
|
||
show: false, // 不显示坐标轴线
|
||
},
|
||
axisLabel: {
|
||
show: false, // 不显示坐标轴上的文字
|
||
},
|
||
splitLine: {
|
||
show: false, // 不显示网格线
|
||
},
|
||
},
|
||
],
|
||
color: "#409eff",
|
||
yAxis: [
|
||
{
|
||
type: "value",
|
||
show: false, // 不显示坐标轴线、坐标轴刻度线和坐标轴上的文字
|
||
axisTick: {
|
||
show: false, // 不显示坐标轴刻度线
|
||
},
|
||
axisLine: {
|
||
show: false, // 不显示坐标轴线
|
||
},
|
||
axisLabel: {
|
||
show: false, // 不显示坐标轴上的文字
|
||
},
|
||
splitLine: {
|
||
show: false, // 不显示网格线
|
||
},
|
||
},
|
||
],
|
||
series: [
|
||
{
|
||
data: data,
|
||
type: "bar",
|
||
barWidth: "30%",
|
||
},
|
||
],
|
||
});
|
||
},
|
||
// 初始化用户数折线图
|
||
initCardUserChart(time = [], data = []) {
|
||
this.cardUserChart = echarts.init(this.$refs.cardUserChart);
|
||
this.cardUserChart.setOption({
|
||
tooltip: {
|
||
trigger: "axis",
|
||
},
|
||
grid: {
|
||
x: 0,
|
||
y: 10,
|
||
x2: 0,
|
||
y2: 2,
|
||
},
|
||
xAxis: [
|
||
{
|
||
type: "category",
|
||
data: time,
|
||
show: false, // 不显示坐标轴线、坐标轴刻度线和坐标轴上的文字
|
||
axisTick: {
|
||
show: false, // 不显示坐标轴刻度线
|
||
},
|
||
axisLine: {
|
||
show: false, // 不显示坐标轴线
|
||
},
|
||
axisLabel: {
|
||
show: false, // 不显示坐标轴上的文字
|
||
},
|
||
splitLine: {
|
||
show: false, // 不显示网格线
|
||
},
|
||
},
|
||
],
|
||
color: "#409eff",
|
||
yAxis: [
|
||
{
|
||
type: "value",
|
||
show: false, // 不显示坐标轴线、坐标轴刻度线和坐标轴上的文字
|
||
axisTick: {
|
||
show: false, // 不显示坐标轴刻度线
|
||
},
|
||
axisLine: {
|
||
show: false, // 不显示坐标轴线
|
||
},
|
||
axisLabel: {
|
||
show: false, // 不显示坐标轴上的文字
|
||
},
|
||
splitLine: {
|
||
show: false, // 不显示网格线
|
||
},
|
||
},
|
||
],
|
||
series: [
|
||
{
|
||
data: data,
|
||
type: "line",
|
||
symbol: "none",
|
||
},
|
||
],
|
||
});
|
||
},
|
||
// 初始化成本折线图
|
||
initCostChart(time = [], data = []) {
|
||
// 销毁旧实例,避免重复创建
|
||
if (this.costRef) {
|
||
this.costRef.dispose();
|
||
}
|
||
this.costRef = echarts.init(this.$refs.costRef);
|
||
|
||
this.costRef.setOption({
|
||
tooltip: {
|
||
trigger: "item",
|
||
// 核心1:显示「时间 + 数量」(时间取X轴分类,数量取当前数值)
|
||
formatter: (params) => {
|
||
// params.name 是X轴时间,params.value 是对应数值(保留2位小数,可按需调整)
|
||
return `${params.name}<br/>${params.value.toFixed(2)}`;
|
||
},
|
||
// 优化提示框样式(可选)
|
||
padding: 10,
|
||
textStyle: { fontSize: 11 },
|
||
backgroundColor: "#fff",
|
||
borderColor: "#eee",
|
||
borderWidth: 1,
|
||
boxShadow: "0 2px 8px rgba(0,0,0,0.08)"
|
||
},
|
||
xAxis: [
|
||
{
|
||
type: "category",
|
||
data: time,
|
||
axisTick: { alignWithLabel: true },
|
||
axisLine: { lineStyle: { color: "#999" } },
|
||
axisLabel: {
|
||
rotate: time.length <= 7 ? 0 : 45,
|
||
interval: 0,
|
||
fontSize: "9",
|
||
},
|
||
},
|
||
],
|
||
grid: {
|
||
top: '5%',
|
||
right: '5%',
|
||
bottom: '8%',
|
||
left: '8%',
|
||
containLabel: true // 确保标签不溢出,不影响点的显示
|
||
},
|
||
color: "#165DFF", // 折线和默认点的颜色
|
||
yAxis: [
|
||
{
|
||
type: "value",
|
||
axisLine: { lineStyle: { color: "#999" } },
|
||
splitLine: { lineStyle: { type: "dashed", color: "#ececec" } },
|
||
},
|
||
],
|
||
series: [
|
||
{
|
||
data: data,
|
||
type: "line",
|
||
symbol: "circle", // 核心2:X轴每个数据点显示圆形标记(默认是none,不显示)
|
||
symbolSize: 6, // 固定点的大小(默认尺寸,可调整)
|
||
lineStyle: { width: 2 }, // 折线宽度(优化视觉)
|
||
// 核心3:鼠标悬浮时点变大 + 黑色边框
|
||
emphasis: {
|
||
symbol: "circle", // 悬浮时仍为圆形
|
||
symbolSize: 10, // 悬浮时点的大小(比默认大)
|
||
itemStyle: {
|
||
borderColor: "#000", // 黑色边框
|
||
borderWidth: 2, // 边框宽度
|
||
// 悬浮时填充色不变(仍为 #165DFF)
|
||
color: "#165DFF"
|
||
}
|
||
},
|
||
// 确保所有数据点都显示(避免自动隐藏)
|
||
showAllSymbol: true,
|
||
// 点的基础样式(默认状态)
|
||
itemStyle: {
|
||
color: "#165DFF", // 点的填充色(与折线一致)
|
||
borderWidth: 1, // 基础状态可加细边框(可选,不加则无)
|
||
borderColor: "#fff" // 基础状态边框颜色(与背景区分,可选)
|
||
}
|
||
},
|
||
],
|
||
});
|
||
},
|
||
// 初始化销售额图标
|
||
initSaleChart(time, data) {
|
||
this.saleChart = null;
|
||
this.saleChart = echarts.init(this.$refs.saleChart);
|
||
this.saleChart.setOption({
|
||
title: {
|
||
text: "销售趋势",
|
||
x: "center",
|
||
},
|
||
tooltip: {
|
||
trigger: "item",
|
||
formatter: (params) => {
|
||
return `${params.value}`;
|
||
},
|
||
},
|
||
xAxis: [
|
||
{
|
||
type: "category",
|
||
data: time,
|
||
axisTick: {
|
||
alignWithLabel: true,
|
||
},
|
||
axisLine: {
|
||
lineStyle: {
|
||
color: "#999",
|
||
},
|
||
},
|
||
axisLabel: {
|
||
rotate: time.length <= 7 ? 0 : 45,
|
||
interval: 0,
|
||
fontSize: "9",
|
||
},
|
||
},
|
||
],
|
||
color: ["#409eff", "#FFC83A", "#F98B26"],
|
||
yAxis: [
|
||
{
|
||
type: "value",
|
||
axisLine: {
|
||
lineStyle: {
|
||
color: "#999",
|
||
},
|
||
},
|
||
splitLine: {
|
||
lineStyle: {
|
||
type: "dashed",
|
||
color: "#ececec",
|
||
},
|
||
},
|
||
},
|
||
],
|
||
series: [
|
||
{
|
||
name: "订单金额",
|
||
type: "bar",
|
||
barWidth: time.length <= 7 ? "50%" : "30%",
|
||
data: data.map((item) => item.orderAmount),
|
||
},
|
||
// {
|
||
// name: '实收金额',
|
||
// type: "bar",
|
||
// barWidth: time.length <= 7 ? "30%" : "20%",
|
||
// data: data.map(item => item.actualAmount),
|
||
// },
|
||
// {
|
||
// name: '优惠金额',
|
||
// type: "bar",
|
||
// barWidth: time.length <= 7 ? "30%" : "20%",
|
||
// data: data.map(item => item.discountAmount),
|
||
// }
|
||
],
|
||
});
|
||
},
|
||
initInterestRateChart(time, data) {
|
||
// 销毁旧实例,避免重复创建
|
||
if (this.initInterestRate) {
|
||
this.initInterestRate.dispose();
|
||
}
|
||
this.initInterestRate = echarts.init(this.$refs.initInterestRate);
|
||
|
||
// 预处理数据:将毛利率和净利率按索引对应(关键,用于手动匹配)
|
||
const profitRateData = data.map(item => item.profitRate || 0);
|
||
const netProfitRateData = data.map(item => item.netProfitRate || 0);
|
||
|
||
this.initInterestRate.setOption({
|
||
tooltip: {
|
||
trigger: "item", // 保留 item 模式(确保能触发,之前已验证有效)
|
||
// 核心:手动查找当前 X 轴索引对应的另一个系列数据,拼接显示
|
||
formatter: (params) => {
|
||
const index = params.dataIndex; // 获取当前数据的索引(X轴位置)
|
||
const xName = time[index]; // 当前 X 轴分类名称(如时间)
|
||
const color1 = "#165DFF"; // 毛利率颜色(与 series 一致)
|
||
const color2 = "#14C9C9"; // 净利率颜色(与 series 一致)
|
||
// 当前系列数据 + 另一个系列数据(按索引匹配)
|
||
const profitRate = profitRateData[index].toFixed(2);
|
||
const netProfitRate = netProfitRateData[index].toFixed(2);
|
||
|
||
// 拼接提示框内容(彩色方块 + 两个指标)
|
||
return `
|
||
<div style="margin-bottom:4px;">${xName}</div>
|
||
<div><span style="display:inline-block;width:8px;height:8px;background:${color1};margin-right:6px;border-radius:2px;"></span>毛利率:${profitRate}%</div>
|
||
`;
|
||
},
|
||
// 保留你原有的提示框样式
|
||
padding: 10,
|
||
textStyle: { fontSize: 11 },
|
||
backgroundColor: "#fff",
|
||
borderColor: "#eee",
|
||
borderWidth: 1,
|
||
boxShadow: "0 2px 8px rgba(0,0,0,0.08)"
|
||
},
|
||
xAxis: [
|
||
{
|
||
type: "category",
|
||
data: time,
|
||
axisTick: { alignWithLabel: true },
|
||
axisLine: { lineStyle: { color: "#999" } },
|
||
axisLabel: {
|
||
rotate: time.length <= 7 ? 0 : 45,
|
||
interval: 0,
|
||
fontSize: "9",
|
||
},
|
||
},
|
||
],
|
||
color: ["#165DFF", "#14C9C9", "#F98B26"], // 系列颜色不变
|
||
yAxis: [
|
||
{
|
||
type: "value",
|
||
axisLine: { lineStyle: { color: "#999" } },
|
||
splitLine: { lineStyle: { type: "dashed", color: "#ececec" } },
|
||
axisLabel: { formatter: "{value}%" }, // Y轴加百分号
|
||
},
|
||
],
|
||
grid: {
|
||
top: '5%',
|
||
right: '5%',
|
||
bottom: '8%',
|
||
left: '8%',
|
||
},
|
||
series: [
|
||
{
|
||
name: "毛利率",
|
||
type: "bar",
|
||
barGap: "0%", // 保持柱子紧贴
|
||
barWidth: time.length <= 7 ? "50%" : "30%",
|
||
data: profitRateData, // 预处理后的毛利率数据
|
||
}
|
||
],
|
||
});
|
||
},
|
||
// 初始化毛利率/净利率图表
|
||
// initInterestRateChart(time, data) {
|
||
// // 销毁旧实例,避免重复创建
|
||
// if (this.initInterestRate) {
|
||
// this.initInterestRate.dispose();
|
||
// }
|
||
// this.initInterestRate = echarts.init(this.$refs.initInterestRate);
|
||
|
||
// // 预处理数据:将毛利率和净利率按索引对应(关键,用于手动匹配)
|
||
// const profitRateData = data.map(item => item.profitRate || 0);
|
||
// const netProfitRateData = data.map(item => item.netProfitRate || 0);
|
||
|
||
// this.initInterestRate.setOption({
|
||
// tooltip: {
|
||
// trigger: "item", // 保留 item 模式(确保能触发,之前已验证有效)
|
||
// // 核心:手动查找当前 X 轴索引对应的另一个系列数据,拼接显示
|
||
// formatter: (params) => {
|
||
// const index = params.dataIndex; // 获取当前数据的索引(X轴位置)
|
||
// const xName = time[index]; // 当前 X 轴分类名称(如时间)
|
||
// const color1 = "#165DFF"; // 毛利率颜色(与 series 一致)
|
||
// const color2 = "#14C9C9"; // 净利率颜色(与 series 一致)
|
||
// // 当前系列数据 + 另一个系列数据(按索引匹配)
|
||
// const profitRate = profitRateData[index].toFixed(2);
|
||
// const netProfitRate = netProfitRateData[index].toFixed(2);
|
||
|
||
// // 拼接提示框内容(彩色方块 + 两个指标)
|
||
// return `
|
||
// <div style="margin-bottom:4px;">${xName}</div>
|
||
// <div><span style="display:inline-block;width:8px;height:8px;background:${color1};margin-right:6px;border-radius:2px;"></span>毛利率:${profitRate}%</div>
|
||
// <div><span style="display:inline-block;width:8px;height:8px;background:${color2};margin-right:6px;border-radius:2px;"></span>净利率:${netProfitRate}%</div>
|
||
// `;
|
||
// },
|
||
// // 保留你原有的提示框样式
|
||
// padding: 10,
|
||
// textStyle: { fontSize: 11 },
|
||
// backgroundColor: "#fff",
|
||
// borderColor: "#eee",
|
||
// borderWidth: 1,
|
||
// boxShadow: "0 2px 8px rgba(0,0,0,0.08)"
|
||
// },
|
||
// xAxis: [
|
||
// {
|
||
// type: "category",
|
||
// data: time,
|
||
// axisTick: { alignWithLabel: true },
|
||
// axisLine: { lineStyle: { color: "#999" } },
|
||
// axisLabel: {
|
||
// rotate: time.length <= 7 ? 0 : 45,
|
||
// interval: 0,
|
||
// fontSize: "9",
|
||
// },
|
||
// },
|
||
// ],
|
||
// color: ["#165DFF", "#14C9C9", "#F98B26"], // 系列颜色不变
|
||
// yAxis: [
|
||
// {
|
||
// type: "value",
|
||
// axisLine: { lineStyle: { color: "#999" } },
|
||
// splitLine: { lineStyle: { type: "dashed", color: "#ececec" } },
|
||
// axisLabel: { formatter: "{value}%" }, // Y轴加百分号
|
||
// },
|
||
// ],
|
||
// grid: {
|
||
// top: '5%',
|
||
// right: '5%',
|
||
// bottom: '8%',
|
||
// left: '8%',
|
||
// },
|
||
// series: [
|
||
// {
|
||
// name: "毛利率",
|
||
// type: "bar",
|
||
// barGap: "0%", // 保持柱子紧贴
|
||
// barWidth: time.length <= 7 ? "50%" : "30%",
|
||
// data: profitRateData, // 预处理后的毛利率数据
|
||
// },
|
||
// {
|
||
// name: '净利率',
|
||
// type: "bar",
|
||
// barGap: "0%",
|
||
// barWidth: time.length <= 7 ? "50%" : "30%",
|
||
// data: netProfitRateData, // 预处理后的净利率数据
|
||
// },
|
||
// ],
|
||
// });
|
||
// },
|
||
// 初始化销售额图表
|
||
initPayChart(data) {
|
||
this.payChart = echarts.init(this.$refs.payChart);
|
||
this.payChart.setOption({
|
||
tooltip: {
|
||
trigger: "item",
|
||
formatter: (params) => {
|
||
return `${params.name}:${params.value}笔`;
|
||
},
|
||
},
|
||
legend: {
|
||
top: "5%",
|
||
left: "center",
|
||
},
|
||
color: [
|
||
"#409eff",
|
||
"#91cc75",
|
||
"#fac858",
|
||
"#ee6666",
|
||
"#73c0de",
|
||
"#3ba272",
|
||
"#fc8452",
|
||
"#9a60b4",
|
||
"#ea7ccc",
|
||
],
|
||
series: [
|
||
{
|
||
type: "pie",
|
||
radius: ["40%", "70%"],
|
||
avoidLabelOverlap: false,
|
||
label: {
|
||
show: false,
|
||
position: "center",
|
||
},
|
||
emphasis: {
|
||
label: {
|
||
show: true,
|
||
fontSize: 20,
|
||
},
|
||
},
|
||
labelLine: {
|
||
show: false,
|
||
},
|
||
data: data,
|
||
},
|
||
],
|
||
});
|
||
},
|
||
// 获取销售额柱状图数据
|
||
async dateAmount() {
|
||
try {
|
||
this.saleLoading = true;
|
||
const res = await dataSummaryApi.dateAmount({ day: this.saleActive, shopId: this.shopId });
|
||
const data = res.map((item) => {
|
||
return {
|
||
orderAmount: item.orderAmount,
|
||
// actualAmount: item.actualAmount,
|
||
// discountAmount: item.discountAmount
|
||
};
|
||
});
|
||
const time = res.map((item) => item.tradeDay);
|
||
this.initSaleChart(time, data);
|
||
} catch (error) {
|
||
console.log(error);
|
||
}
|
||
setTimeout(() => {
|
||
this.saleLoading = false;
|
||
}, 300);
|
||
},
|
||
// 获取毛利率/净利率柱状图数据
|
||
async profitRateBarChart() {
|
||
try {
|
||
this.initInterestRateLoading = true;
|
||
const res = await dataSummaryApi.profitRateBarChart({ day: this.interestRateDay, shopId: this.shopId });
|
||
|
||
this.initInterestRateTime = dayjs().format('HH:mm')
|
||
|
||
const data = res.map((item) => {
|
||
return {
|
||
profitRate: item.profitRate || 0,
|
||
netProfitRate: item.netProfitRate || 0,
|
||
// discountAmount: item.discountAmount
|
||
};
|
||
});
|
||
const time = res.map((item) => item.tradeDay);
|
||
this.initInterestRateChart(time, data);
|
||
} catch (error) {
|
||
console.log(error);
|
||
}
|
||
setTimeout(() => {
|
||
this.initInterestRateLoading = false;
|
||
}, 300);
|
||
},
|
||
// 获取成本折线图数据
|
||
async costLineChart() {
|
||
try {
|
||
this.costLoading = true;
|
||
const res = await dataSummaryApi.costLineChart({ day: this.costDay, shopId: this.shopId });
|
||
|
||
this.costUpdateTime = dayjs().format('HH:mm')
|
||
|
||
const data = res.map((item) => item.productCostAmount || 0);
|
||
const time = res.map((item) => item.tradeDay);
|
||
this.initCostChart(time, data);
|
||
} catch (error) {
|
||
console.log(error);
|
||
}
|
||
setTimeout(() => {
|
||
this.costLoading = false;
|
||
}, 300);
|
||
},
|
||
paginationChange(e) {
|
||
this.saleTablePage = e;
|
||
this.dateProduct();
|
||
},
|
||
// 获取销售额排行表格数据
|
||
async dateProduct() {
|
||
try {
|
||
this.saleTableLoading = true;
|
||
const res = await dataSummaryApi.productSaleDate({
|
||
day: this.saleTableActive,
|
||
shopId: this.shopId,
|
||
});
|
||
this.saleTable = res;
|
||
this.saleTableTotal = res.length;
|
||
// this.summaryDateGet(res.countList);
|
||
setTimeout(() => {
|
||
this.saleTableLoading = false;
|
||
}, 300);
|
||
} catch (error) {
|
||
console.log(error);
|
||
}
|
||
},
|
||
// 支付类型占比 饼图
|
||
async datePayType() {
|
||
try {
|
||
this.payChartLoading = true;
|
||
const res = await dataSummaryApi.datePayType({ day: this.saleActive, shopId: this.shopId });
|
||
const data = res.map((item) => {
|
||
return {
|
||
value: item.count,
|
||
name: item.payType,
|
||
};
|
||
});
|
||
setTimeout(() => {
|
||
this.payChartLoading = false;
|
||
}, 300);
|
||
this.initPayChart(data);
|
||
} catch (error) {
|
||
console.log(error);
|
||
}
|
||
},
|
||
// 汇总数据
|
||
async summaryGet() {
|
||
try {
|
||
const res1 = await summaryGet();
|
||
const res2 = await summaryTodayGet();
|
||
this.topData = {
|
||
...res1,
|
||
...res2,
|
||
};
|
||
let payTime = res1.countDateList.map((item) => item.tradeDay);
|
||
let payData = res1.countDateList.map((item) => item.count);
|
||
|
||
let countTime = res1.visitsCountList.map((item) => item.tradeDay);
|
||
let countData = res1.visitsCountList.map((item) => item.count);
|
||
|
||
this.initCardPayChart(payTime, payData);
|
||
this.initCardCountChart(countTime, countData);
|
||
console.log(this.topData);
|
||
} catch (error) {
|
||
console.log(error);
|
||
}
|
||
},
|
||
rankChange() {
|
||
this.dateProduct();
|
||
// this.summaryDateGet();
|
||
},
|
||
// 初始化销售图标
|
||
initProduceChart(p1, p2) {
|
||
this.productCountChart = echarts.init(this.$refs.productCountChart);
|
||
// this.productSumChart = echarts.init(this.$refs.productSumChart);
|
||
|
||
this.productCountChart.setOption({
|
||
tooltip: {
|
||
trigger: "axis",
|
||
},
|
||
grid: {
|
||
x: 0,
|
||
y: 0,
|
||
x2: 0,
|
||
y2: 0,
|
||
},
|
||
xAxis: [
|
||
{
|
||
boundaryGap: false,
|
||
type: "category",
|
||
data: p1[0],
|
||
show: false, // 不显示坐标轴线、坐标轴刻度线和坐标轴上的文字
|
||
axisTick: {
|
||
show: false, // 不显示坐标轴刻度线
|
||
},
|
||
axisLine: {
|
||
show: false, // 不显示坐标轴线
|
||
},
|
||
axisLabel: {
|
||
show: false, // 不显示坐标轴上的文字
|
||
},
|
||
splitLine: {
|
||
show: false, // 不显示网格线
|
||
},
|
||
},
|
||
],
|
||
color: "#409eff",
|
||
yAxis: [
|
||
{
|
||
type: "value",
|
||
show: false, // 不显示坐标轴线、坐标轴刻度线和坐标轴上的文字
|
||
axisTick: {
|
||
show: false, // 不显示坐标轴刻度线
|
||
},
|
||
axisLine: {
|
||
show: false, // 不显示坐标轴线
|
||
},
|
||
axisLabel: {
|
||
show: false, // 不显示坐标轴上的文字
|
||
},
|
||
splitLine: {
|
||
show: false, // 不显示网格线
|
||
},
|
||
},
|
||
],
|
||
series: [
|
||
{
|
||
data: p1[1],
|
||
type: "line",
|
||
symbol: "none",
|
||
smooth: true,
|
||
areaStyle: {
|
||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||
{
|
||
offset: 0,
|
||
color: "#409eff", // 渐变颜色
|
||
},
|
||
{
|
||
offset: 1,
|
||
color: "#409eff", // 渐变颜色
|
||
},
|
||
]),
|
||
},
|
||
},
|
||
],
|
||
});
|
||
|
||
// this.productSumChart.setOption({
|
||
// tooltip: {
|
||
// trigger: "axis"
|
||
// },
|
||
// grid: {
|
||
// x: 0,
|
||
// y: 0,
|
||
// x2: 0,
|
||
// y2: 0
|
||
// },
|
||
// xAxis: [
|
||
// {
|
||
// boundaryGap: false,
|
||
// type: "category",
|
||
// data: p2[0],
|
||
// show: false, // 不显示坐标轴线、坐标轴刻度线和坐标轴上的文字
|
||
// axisTick: {
|
||
// show: false // 不显示坐标轴刻度线
|
||
// },
|
||
// axisLine: {
|
||
// show: false // 不显示坐标轴线
|
||
// },
|
||
// axisLabel: {
|
||
// show: false // 不显示坐标轴上的文字
|
||
// },
|
||
// splitLine: {
|
||
// show: false // 不显示网格线
|
||
// }
|
||
// }
|
||
// ],
|
||
// color: "#409eff",
|
||
// yAxis: [
|
||
// {
|
||
// type: "value",
|
||
// show: false, // 不显示坐标轴线、坐标轴刻度线和坐标轴上的文字
|
||
// axisTick: {
|
||
// show: false // 不显示坐标轴刻度线
|
||
// },
|
||
// axisLine: {
|
||
// show: false // 不显示坐标轴线
|
||
// },
|
||
// axisLabel: {
|
||
// show: false // 不显示坐标轴上的文字
|
||
// },
|
||
// splitLine: {
|
||
// show: false // 不显示网格线
|
||
// }
|
||
// }
|
||
// ],
|
||
// series: [
|
||
// {
|
||
// data: p2[1],
|
||
// type: "line",
|
||
// symbol: "none",
|
||
// smooth: true,
|
||
// areaStyle: {
|
||
// color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||
// {
|
||
// offset: 0,
|
||
// color: "#409eff" // 渐变颜色
|
||
// },
|
||
// {
|
||
// offset: 1,
|
||
// color: "#409eff" // 渐变颜色
|
||
// }
|
||
// ])
|
||
// }
|
||
// }
|
||
// ]
|
||
// });
|
||
},
|
||
// 日期汇总数据
|
||
async summaryDateGet(res) {
|
||
try {
|
||
console.log(res);
|
||
// this.initProduceChart(p1, p2);
|
||
} catch (error) {
|
||
console.log(error);
|
||
}
|
||
},
|
||
},
|
||
};
|
||
</script>
|
||
|
||
<style>
|
||
.popper {
|
||
border: 1px solid #d9d9d9 !important;
|
||
}
|
||
</style>
|
||
<style scoped lang="scss">
|
||
.tips_row {
|
||
width: 300px;
|
||
padding: 0 10px;
|
||
|
||
.item {
|
||
height: 40px;
|
||
display: flex;
|
||
align-items: center;
|
||
color: #666;
|
||
justify-content: space-between;
|
||
|
||
&:not(:last-child) {
|
||
border-bottom: 1px solid #d9d9d9;
|
||
}
|
||
|
||
.left {
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.icon {
|
||
font-size: 20px;
|
||
margin-right: 10px;
|
||
}
|
||
}
|
||
|
||
.num {
|
||
color: #1890ff;
|
||
}
|
||
}
|
||
}
|
||
|
||
.app-container {
|
||
padding: 20px;
|
||
background-color: #f5f5f5;
|
||
}
|
||
|
||
.h_card_wrap {
|
||
.status_wrap {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
|
||
.left {
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.dot {
|
||
$size: 6px;
|
||
width: $size;
|
||
height: $size;
|
||
border-radius: 50%;
|
||
background-color: #1890ff;
|
||
margin-right: 10px;
|
||
}
|
||
}
|
||
|
||
.time {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
}
|
||
|
||
.content {
|
||
background-color: #fff;
|
||
margin-top: 15px;
|
||
padding: 20px;
|
||
|
||
.top {
|
||
display: flex;
|
||
|
||
.item {
|
||
flex: 1;
|
||
|
||
&.earnings {
|
||
display: flex;
|
||
}
|
||
|
||
&.data {
|
||
margin-left: 40px;
|
||
background: url("../../assets/images/data_home_bg1.png") no-repeat center center / cover;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.data_item {
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.data_item_right {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
|
||
.t {
|
||
width: 200px;
|
||
color: #333;
|
||
display: flex;
|
||
|
||
&:not(:first-child) {
|
||
margin-top: 20px;
|
||
}
|
||
}
|
||
|
||
.n {
|
||
color: #1890ff;
|
||
margin-left: 20px;
|
||
}
|
||
}
|
||
|
||
.num_wrap {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
.num {
|
||
font-size: 30px;
|
||
color: #1890ff;
|
||
}
|
||
|
||
.tips {
|
||
font-size: 12px;
|
||
margin-top: 10px;
|
||
}
|
||
}
|
||
|
||
.line_wrap {
|
||
flex: 1;
|
||
padding-left: 20px;
|
||
|
||
.line_item {
|
||
&:not(:first-child) {
|
||
margin-top: 20px;
|
||
}
|
||
|
||
.line_item_top {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
font-size: 12px;
|
||
|
||
.t {
|
||
color: #999;
|
||
}
|
||
}
|
||
|
||
.line_gropress {
|
||
display: flex;
|
||
margin-top: 6px;
|
||
background-color: #f6f6f6;
|
||
|
||
.gropress {
|
||
height: 5px;
|
||
|
||
&.l {
|
||
background-color: #1890ff;
|
||
}
|
||
|
||
&.r {
|
||
background-color: #ff3f3f;
|
||
}
|
||
}
|
||
}
|
||
|
||
.line_btm {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
margin-top: 5px;
|
||
|
||
.icon {
|
||
color: #a2a2a2;
|
||
position: relative;
|
||
left: -5px;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.info {
|
||
font-size: 12px;
|
||
|
||
.l_t {
|
||
color: #1890ff;
|
||
}
|
||
|
||
.l_r {
|
||
color: #ff3f3f;
|
||
margin-left: 10px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.btm {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
margin-top: 20px;
|
||
|
||
.item {
|
||
width: 200px;
|
||
height: 83px;
|
||
background-repeat: no-repeat;
|
||
background-position: center center;
|
||
background-size: 100% 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
padding-left: 18px;
|
||
|
||
&.item1 {
|
||
background-image: url("../../assets/images/data_home_item1.png");
|
||
}
|
||
|
||
&.item2 {
|
||
background-image: url("../../assets/images/data_home_item2.png");
|
||
}
|
||
|
||
&.item3 {
|
||
background-image: url("../../assets/images/data_home_item3.png");
|
||
}
|
||
|
||
&.item4 {
|
||
background-image: url("../../assets/images/data_home_item4.png");
|
||
}
|
||
|
||
&.item5 {
|
||
background-image: url("../../assets/images/data_home_item5.png");
|
||
}
|
||
|
||
&.item6 {
|
||
background-image: url("../../assets/images/data_home_item6.png");
|
||
}
|
||
|
||
.row_wrap {
|
||
display: flex;
|
||
width: 100%;
|
||
height: 100%;
|
||
|
||
.row {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
|
||
.t {
|
||
margin-left: 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
.title {
|
||
display: flex;
|
||
align-items: center;
|
||
color: #333;
|
||
font-size: 14px;
|
||
gap: 8px;
|
||
|
||
.icon {
|
||
font-size: 12px;
|
||
color: #999;
|
||
margin-left: 6px;
|
||
}
|
||
}
|
||
|
||
.icon_wrap {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-top: 10px;
|
||
|
||
.img {
|
||
width: 36px;
|
||
height: 36px;
|
||
}
|
||
|
||
.t {
|
||
font-size: 24px;
|
||
margin-left: 10px;
|
||
font-weight: bold;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.card_wrap {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 20px;
|
||
|
||
.card {
|
||
flex: 1;
|
||
background-color: #fff;
|
||
border-radius: 2px;
|
||
padding: 0 20px;
|
||
|
||
.header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
color: #999;
|
||
padding-top: 20px;
|
||
|
||
.card_title {
|
||
font-size: 14px;
|
||
flex: 1;
|
||
}
|
||
}
|
||
|
||
.number {
|
||
padding: 20px 0 10px 0;
|
||
font-size: 24px;
|
||
height: 60px;
|
||
}
|
||
|
||
.row {
|
||
height: 50px;
|
||
color: #555;
|
||
font-size: 14px;
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
&:not(:last-child) {
|
||
border-bottom: 1px solid #ececec;
|
||
}
|
||
|
||
.icon {
|
||
color: rgb(255, 85, 85);
|
||
margin-left: 4px;
|
||
}
|
||
|
||
.dot {
|
||
$size: 6px;
|
||
width: $size;
|
||
height: $size;
|
||
border-radius: 50%;
|
||
background-color: #1890ff;
|
||
margin-right: 6px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.chart_wrap {
|
||
margin-top: 20px;
|
||
display: flex;
|
||
gap: 20px;
|
||
|
||
.sale_data {
|
||
display: flex;
|
||
|
||
.card {
|
||
flex: 1;
|
||
background-color: #fff;
|
||
border-radius: 2px;
|
||
padding: 0 20px;
|
||
|
||
.sale_data_header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
color: #999;
|
||
padding-top: 20px;
|
||
|
||
.card_title {
|
||
font-size: 14px;
|
||
flex: 1;
|
||
}
|
||
}
|
||
|
||
.number {
|
||
padding-top: 10px;
|
||
font-size: 24px;
|
||
height: 60px;
|
||
}
|
||
|
||
.product_chart_wrap {
|
||
height: 50px;
|
||
}
|
||
}
|
||
}
|
||
|
||
.item {
|
||
flex: 1;
|
||
background-color: #fff;
|
||
border-radius: 2px;
|
||
|
||
.header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
border-bottom: 1px solid #ececec;
|
||
padding: 0 20px;
|
||
|
||
.rate_title {
|
||
flex: 1;
|
||
padding: 20px 0;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
|
||
.column {
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.t1 {
|
||
font-size: 16px;
|
||
color: #111;
|
||
}
|
||
|
||
.t2 {
|
||
font-size: 12px;
|
||
color: #999;
|
||
}
|
||
}
|
||
|
||
.tab_wrap {
|
||
display: flex;
|
||
$color: #1890ff;
|
||
|
||
.item {
|
||
padding: 0 10px;
|
||
height: 60px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 14px;
|
||
margin-right: 20px;
|
||
|
||
&.active {
|
||
position: relative;
|
||
color: $color;
|
||
|
||
&::after {
|
||
content: "";
|
||
width: 100%;
|
||
border-bottom: 2px solid $color;
|
||
position: absolute;
|
||
bottom: 0;
|
||
left: 0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.chart {
|
||
padding: 20px 0;
|
||
height: 300px;
|
||
}
|
||
|
||
.table {
|
||
padding: 20px;
|
||
}
|
||
}
|
||
}
|
||
|
||
.right_data_wrap {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.item {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
|
||
.num {
|
||
font-size: 32px;
|
||
color: var(--el-color-primary);
|
||
font-weight: bold;
|
||
}
|
||
|
||
.tips {
|
||
font-size: 14px;
|
||
color: #666666;
|
||
}
|
||
}
|
||
}
|
||
|
||
.date_list {
|
||
display: flex;
|
||
margin-right: 10px;
|
||
|
||
.item {
|
||
font-size: 14px;
|
||
color: #999999;
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
&.active {
|
||
.date-tab-item {
|
||
color: var(--el-color-primary);
|
||
}
|
||
}
|
||
|
||
.date-tab-item {
|
||
cursor: pointer;
|
||
|
||
&:hover {
|
||
color: var(--el-color-primary-light-3);
|
||
}
|
||
}
|
||
|
||
.separator {
|
||
margin: 0 6px;
|
||
position: relative;
|
||
top: -1px;
|
||
}
|
||
}
|
||
}
|
||
</style>
|