564 lines
22 KiB
Vue
564 lines
22 KiB
Vue
<template>
|
||
<div class="main">
|
||
<!-- <div style="position: fixed;right: 0;top: 20%;z-index:99999999999">-->
|
||
<!-- <commercial-type :have="1"/>-->
|
||
<!-- </div>-->
|
||
<header-top ref="headerTop" :bgUrl="bgUrl" :menu="menu" :topBg="topBg" :bgColor="bgColor" :title="title" :page="page" :backType="backType" :analyseInfo="analyseInfo"
|
||
:serverpartName="serviceInfo.SERVERPART_NAME" :spregionTypeName="serviceInfo.SPREGIONTYPE_NAME" :serviceInfo="serviceInfo"
|
||
:topLeftBg="topLeftBg" :topLeftColor="topLeftColor" :iconObj="iconObj" :haveIconObj="haveIconObj" :detailBoxBg="detailBoxBg"
|
||
:haveFun="haveFun" :serviceTypeObj="serviceTypeObj" :serviceInfoObj="serviceInfoObj" :pageType="pageType" :pageIndex="2"/>
|
||
|
||
<div class="charts">
|
||
<div class="chartsItem">
|
||
<div style="display: flex;align-items: center;justify-content: space-between">
|
||
<p class="title">客单分析</p>
|
||
<div class="item">
|
||
<text class="value">{{time}}</text>
|
||
</div>
|
||
</div>
|
||
<div v-if="customer">
|
||
<customer-first :analyseInfo="{analysisins_type: 1202,analysisins_format: 2000}" :data="customer" />
|
||
</div>
|
||
<no-data v-else />
|
||
</div>
|
||
<div class="chartsItem" style="margin-top: 32px">
|
||
<div class="time">
|
||
<div class="select">
|
||
<picker mode="date" fields="month" :value="single" :end="endData" @change="bindDateChange" >
|
||
<view class="time">
|
||
<view class="uni-input" style="background: transparent;padding: 0;height:100%">{{ single }}</view>
|
||
<image class="icon" src="https://eshangtech.com/ShopICO/ahyd-BID/index/arrow_bottom.svg"></image>
|
||
</view>
|
||
</picker>
|
||
</div>
|
||
</div>
|
||
<p class="title">客群特征分析</p>
|
||
<div v-if="genderBubbleList.res && genderBubbleList.res.length>0">
|
||
<customer-second :data="genderBubbleList" />
|
||
<analyse :analyseInfo="{analysisins_type: 1203,analysisins_format: 2000}" />
|
||
</div>
|
||
<no-data v-else />
|
||
</div>
|
||
<div class="chartsItem" style="margin-top: 32px">
|
||
<p class="title">客群消费偏好</p>
|
||
<div v-if="consterPreferList.series && consterPreferList.series.length>0">
|
||
<consum-prefer :data="consterPreferList" />
|
||
<analyse :analyseInfo="{analysisins_type: 1204,analysisins_format: 2000}" />
|
||
</div>
|
||
<no-data v-else/>
|
||
</div>
|
||
<div class="chartsItem" style="margin-top: 32px">
|
||
<p class="title">客群消费水平</p>
|
||
<div v-if="consumptionLevelList && consumptionLevelList.length>0">
|
||
<consumption-level :data="consumptionLevelList"/>
|
||
<analyse :analyseInfo="{analysisins_type: 1205,analysisins_format: 2000}" />
|
||
</div>
|
||
<no-data v-else />
|
||
</div>
|
||
<div class="chartsItem" style="margin-top: 32px">
|
||
<p class="title">业态客单偏好</p>
|
||
<div v-if="businessTypeList && businessTypeList.length>0">
|
||
<business-type :data="businessTypeList"></business-type>
|
||
<analyse :analyseInfo="{analysisins_type: 1206,analysisins_format: 2000}" />
|
||
</div>
|
||
<no-data v-else />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import request from '@/util/index.js'
|
||
import headerTop from "./components/headerTop.vue";
|
||
import customerFirst from "./components/guest/customerFirst.vue";
|
||
import customerSecond from "./components/guest/customerSecond.vue";
|
||
import analyse from "./components/analyse.vue";
|
||
import ConsumPrefer from "./components/guest/consumPrefer.vue";
|
||
import ConsumptionLevel from "./components/guest/consumptionLevel.vue";
|
||
import BusinessType from "./components/guest/businessType.vue";
|
||
import NoData from "./components/noData.vue";
|
||
import commercialType from "./commercialType.vue";
|
||
import {getFieldEnum} from "../../util/dateTime";
|
||
import SliderPage from "./components/sliderPage.vue";
|
||
export default {
|
||
name: "guestPortrait",
|
||
components:{
|
||
SliderPage,
|
||
NoData, BusinessType, ConsumptionLevel, ConsumPrefer, analyse, headerTop,customerFirst,customerSecond,commercialType},
|
||
data() {
|
||
return {
|
||
topBg:'linear-gradient(180deg, #A1D0C1 0%, #B1D9CD 100%);',//顶部组件的悬浮背景色
|
||
title:'客群画像',//页面标题
|
||
bgColor:'180deg, #30C8ED 0%, #0B9353 100%',//标签背景颜色
|
||
bgUrl:'https://eshangtech.com/ShopICO/ahyd-BID/newCommercialBI/guestPortraitBg.svg',//背景图片路径
|
||
page:'/pages/commercialBI/guestPortrait',
|
||
|
||
pageType:1000,
|
||
detailBoxBg:'linear-gradient(136deg, #ECF6F6 0%, #FFFFFF 100%);',
|
||
topLeftBg:'linear-gradient(180deg, rgba(48, 200, 237, 0.2) 0%, rgba(11, 147, 83, 0.2) 100%)',// 类别背景
|
||
topLeftColor:'#0E9760',// 类别文字颜色
|
||
iconObj:{
|
||
car:'https://eshangtech.com/ShopICO/ahyd-BID/newCommercialBI/carGuest.svg',
|
||
charge:'https://eshangtech.com/ShopICO/ahyd-BID/newCommercialBI/chargeGuest.svg',
|
||
bady:'https://eshangtech.com/ShopICO/ahyd-BID/newCommercialBI/badyGuest.svg',
|
||
guestRoom:'https://eshangtech.com/ShopICO/ahyd-BID/newCommercialBI/guestRoomGuest.svg'
|
||
},
|
||
haveIconObj:{
|
||
have:'https://eshangtech.com/ShopICO/ahyd-BID/newCommercialBI/haveGuest.svg',
|
||
noHave:'https://eshangtech.com/ShopICO/ahyd-BID/newCommercialBI/noHaveGuest.svg'
|
||
},
|
||
time:'',//跳转携带的时间
|
||
menu:{},//手机配置信息
|
||
customer:{}, // 客群分析第一个
|
||
genderBubbleList:[],//男女的气泡图
|
||
consterPreferList:{},//客群消费偏好
|
||
consumptionLevelList:[],//客群消费水平
|
||
businessTypeList:[],//业态偏好
|
||
serviceInfo:{}, //当前服务区信息
|
||
backType:'',//返回的页面类型
|
||
analyseInfo:{
|
||
analysisins_type: 1201,
|
||
},
|
||
single:'',//显示时间
|
||
thisMonth:'',//几月
|
||
endData:'', // 结束时间
|
||
haveFun:{},
|
||
serviceTypeObj:{},// 服务区类型对象
|
||
serviceInfoObj:{}
|
||
}
|
||
},
|
||
onLoad(option){
|
||
if (option.serviceInfo){
|
||
this.serviceInfo = JSON.parse(option.serviceInfo)
|
||
}
|
||
this.backType = option.type
|
||
//跳转的时候带上时间
|
||
this.time = option.time
|
||
this.endData = new Date()
|
||
// 服务区类型枚举
|
||
this.handleServiceType()
|
||
},
|
||
onShow(){
|
||
let storeTime = uni.getStorageSync('lastDay')
|
||
if (storeTime){
|
||
this.time = storeTime
|
||
}
|
||
this.single = this.$util.getThisMonthHave(this.time)
|
||
console.log('this.single',this.single)
|
||
const date = new Date(this.single)
|
||
//设置日期选择器的开始时间和结束时间
|
||
let m = date.getMonth() + 1
|
||
if (m<10){
|
||
m = '0' + m
|
||
}
|
||
this.thisMonth = m
|
||
let storeServiceInfo = uni.getStorageSync('currentService')
|
||
if (storeServiceInfo){
|
||
this.serviceInfo = storeServiceInfo
|
||
}
|
||
// 获取手机参数对页面进行适配
|
||
let systemInfo = uni.getSystemInfoSync()
|
||
// 把获取到的手机参数保存
|
||
uni.setStorageSync('phoneInfo',systemInfo)
|
||
this.statusBarHeight = Number(systemInfo.statusBarHeight)
|
||
this.menu = uni.getMenuButtonBoundingClientRect()
|
||
// 把获取图表数据的方法统一放在一起 然后去请求接口拿到数据 再分批传到相对应的图标组件
|
||
// 每个图表都是用组件的方式引入的 数据是通过prop传入的
|
||
// 每个组件需要的数据格式都注释在方法的下面 方便修改,接口拿到数据之后 就是对数据进行处理 普通的遍历数组和遍历对象的方法
|
||
if (!storeServiceInfo){
|
||
this.nearestService()
|
||
}
|
||
//customer
|
||
this.getCustomer()
|
||
//客群分析男女的气泡图
|
||
this.getGenderBubbleList()
|
||
//客群消费偏好
|
||
this.getConsterPreferList()
|
||
//客群消费水平
|
||
this.getConsumptionLevelList()
|
||
//业态偏好
|
||
this.getBusinessTypeList()
|
||
// 服务区基本信息
|
||
this.getServiceInfo()
|
||
this.handleChangeCurrent()
|
||
},
|
||
onUnload() {
|
||
this.$util.addUserBehavior()
|
||
},
|
||
methods:{
|
||
handleChangeCurrent(){
|
||
this.$refs.headerTop.handleChangeCurrent()
|
||
},
|
||
bindDateChange(e){
|
||
const date = new Date(e.detail.value)
|
||
let m = date.getMonth() + 1
|
||
if (m<10){
|
||
m = '0' + m
|
||
}
|
||
this.thisMonth = m
|
||
this.single = e.detail.value
|
||
let d = this.$util.getThisMonthDay(e.detail.value)
|
||
this.endTime = e.detail.value + '-' + d
|
||
this.onRefresh()
|
||
},
|
||
// 枚举服务区类型 SERVERPART_TYPE
|
||
async handleServiceType(){
|
||
const data = await getFieldEnum({ FieldExplainField: 'SERVERPART_TYPE' });
|
||
console.log('data',data)
|
||
let obj = {}
|
||
data.forEach(item=>{
|
||
obj[Number(item.value)] = item.label
|
||
})
|
||
console.log('obj',obj)
|
||
this.serviceTypeObj = obj
|
||
},
|
||
//重新调一遍页面数据的方法
|
||
onRefresh(){
|
||
//客群分析男女的气泡图
|
||
this.getGenderBubbleList()
|
||
//客群消费偏好
|
||
this.getConsterPreferList()
|
||
//客群消费水平
|
||
this.getConsumptionLevelList()
|
||
//业态偏好
|
||
this.getBusinessTypeList()
|
||
// 服务区基本信息
|
||
this.getServiceInfo()
|
||
},
|
||
//获取服务区基本信息
|
||
async getServiceInfo(){
|
||
let req = {
|
||
ServerpartId:this.serviceInfo.Serverpart_ID
|
||
}
|
||
const total = await request.$webGet('CommercialApi/BaseInfo/GetServerpartInfo',req)
|
||
this.serviceInfoObj = total.Result_Data
|
||
this.haveFun = {
|
||
car:total.Result_Data.HASPILOTLOUNGE,
|
||
charge:total.Result_Data.HASCHARGE ,
|
||
bady:total.Result_Data.HASMOTHER ,
|
||
gusetHome:total.Result_Data.HASGUESTROOM
|
||
}
|
||
},
|
||
//当前最近的服务区数据
|
||
async nearestService(){
|
||
let seat = uni.getStorageSync('seatInfo');
|
||
let req = {
|
||
longitude:seat.longitude,
|
||
Province_Code:'340000',
|
||
latitude:seat.latitude,
|
||
}
|
||
const data = await request.$webGet('CommercialApi/BaseInfo/GetServerpartList',req)
|
||
let res = {
|
||
SERVERPART_NAME:data.Result_Data.List[0].SERVERPART_NAME,//服务区
|
||
SPREGIONTYPE_NAME:data.Result_Data.List[0].SPREGIONTYPE_NAME,//片区
|
||
Serverpart_ID:data.Result_Data.List[0].SERVERPART_ID,
|
||
longitude:data.Result_Data.List[0].SERVERPART_X,
|
||
latitude:data.Result_Data.List[0].SERVERPART_Y,
|
||
}
|
||
uni.setStorageSync('currentService',res)
|
||
},
|
||
//customer
|
||
// 用async await直接等待接口数据返回之后再对数据直接进行处理 节约时间
|
||
async getCustomer(){
|
||
let time = ''
|
||
const date = new Date(this.single)
|
||
let y = date.getFullYear()
|
||
let m = date.getMonth() + 1
|
||
const nowDate = new Date(this.time)
|
||
let nowYear = nowDate.getFullYear()
|
||
let nowMonth = nowDate.getMonth() + 1
|
||
if (y===nowYear && m===nowMonth){
|
||
time = this.time
|
||
}else{
|
||
time = this.endTime
|
||
}
|
||
console.log('time',time)
|
||
const req = {
|
||
Province_Code:'340000',
|
||
Statistics_Date:time,
|
||
Serverpart_ID:this.serviceInfo.SERVERPART_NAME==='安徽驿达'?null:this.serviceInfo.Serverpart_ID,
|
||
ShowConsumptionLevel:true,
|
||
ShowConvertRate:true
|
||
}
|
||
let totalData = await request.$webGet('CommercialApi/Revenue/GetTransactionAnalysis',req)
|
||
console.log('totalData',totalData)
|
||
this.customer = totalData.Result_Data?totalData.Result_Data:{}
|
||
|
||
},
|
||
//客群分析男女的气泡图
|
||
async getGenderBubbleList(){
|
||
let time = ''
|
||
const date = new Date(this.single)
|
||
let y = date.getFullYear()
|
||
let m = date.getMonth() + 1
|
||
const nowDate = new Date(this.time)
|
||
let nowYear = nowDate.getFullYear()
|
||
let nowMonth = nowDate.getMonth() + 1
|
||
if (y===nowYear && m===nowMonth){
|
||
time = this.time
|
||
}else{
|
||
time = this.endTime
|
||
}
|
||
let result = {
|
||
man:'',
|
||
woman:'',
|
||
res:[]
|
||
}
|
||
const req = {
|
||
statisticsType:1,
|
||
provinceCode:'340000',
|
||
serverpartId:this.serviceInfo.SERVERPART_NAME==='安徽驿达'?null:this.serviceInfo.Serverpart_ID,
|
||
statisticsMonth:this.$util.getThisMonth(time)
|
||
}
|
||
let totalData = await request.$webGet('CommercialApi/Customer/GetCustomerRatio',req)
|
||
totalData.Result_Data.List.forEach(item=>{
|
||
// 判断男性和女性 然后赋值
|
||
if (item.name === '男性'){
|
||
result.man = item.data[0]
|
||
}else if(item.name === '女性'){
|
||
result.woman = item.data[0]
|
||
}
|
||
})
|
||
const bubbleReq = {
|
||
provinceCode:'340000',
|
||
serverpartId:this.serviceInfo.SERVERPART_NAME==='安徽驿达'?null:this.serviceInfo.Serverpart_ID,
|
||
statisticsMonth:this.$util.getThisMonth(time)
|
||
}
|
||
|
||
let bubbleData = await request.$webGet('CommercialApi/Customer/GetCustomerGroupRatio',bubbleReq)
|
||
result.res = bubbleData.Result_Data.List
|
||
// let res = [
|
||
// {
|
||
// name: "男",
|
||
// data: [[25,60,30],[40,35,17]]
|
||
// },
|
||
// {
|
||
// name: "女",
|
||
// data: [[25,35,17],[35,15,15]]
|
||
// }
|
||
// ]
|
||
this.genderBubbleList = result
|
||
},
|
||
//客群消费偏好
|
||
async getConsterPreferList(){
|
||
let time = ''
|
||
const date = new Date(this.single)
|
||
let y = date.getFullYear()
|
||
let m = date.getMonth() + 1
|
||
const nowDate = new Date(this.time)
|
||
let nowYear = nowDate.getFullYear()
|
||
let nowMonth = nowDate.getMonth() + 1
|
||
if (y===nowYear && m===nowMonth){
|
||
time = this.time
|
||
}else{
|
||
time = this.endTime
|
||
}
|
||
let req
|
||
if (this.serviceInfo.SERVERPART_NAME==='安徽驿达'){
|
||
req = {
|
||
statisticsType:1,
|
||
startMonth:this.$util.getThisMonth(time),
|
||
endMonth:this.$util.getThisMonth(time),
|
||
provinceCode: '340000',
|
||
}
|
||
}else{
|
||
req = {
|
||
statisticsType:1,
|
||
startMonth:this.$util.getThisMonth(time),
|
||
endMonth:this.$util.getThisMonth(time),
|
||
provinceCode: '340000',
|
||
serverpartId: this.serviceInfo.Serverpart_ID || ''
|
||
}
|
||
}
|
||
const data = await request.$webGet('CommercialApi/Customer/GetCustomerSaleRatio',req)
|
||
let res = {
|
||
categories:[],
|
||
series:[
|
||
{name: "男", data: []},
|
||
{name: "女", data: []}
|
||
],
|
||
max:''
|
||
}
|
||
if (data.Result_Data){
|
||
data.Result_Data.CustomerSaleList.forEach(item=>{
|
||
res.categories.push(item.BusinessTradeName)
|
||
res.series[0].data.push(item.MaleRatio)
|
||
res.series[1].data.push(item.FemaleRatio)
|
||
})
|
||
res.max = data.Result_Data.MaxSexRatio
|
||
// let res = {
|
||
// categories: ['餐饮','商超','水果饮品','连锁品牌','粽子','小吃'],
|
||
// series: [
|
||
// {name: "男", data: [90,110,165,195,187,172]},
|
||
// {name: "女", data: [190,210,105,35,27,102]}
|
||
// ]
|
||
// }
|
||
this.consterPreferList = res
|
||
}else{
|
||
this.consterPreferList = {}
|
||
}
|
||
|
||
},
|
||
//客群消费水平
|
||
async getConsumptionLevelList(){
|
||
let time = ''
|
||
const date = new Date(this.single)
|
||
let y = date.getFullYear()
|
||
let m = date.getMonth() + 1
|
||
const nowDate = new Date(this.time)
|
||
let nowYear = nowDate.getFullYear()
|
||
let nowMonth = nowDate.getMonth() + 1
|
||
if (y===nowYear && m===nowMonth){
|
||
time = this.time
|
||
}else{
|
||
time = this.endTime
|
||
}
|
||
const req = {
|
||
provinceCode:'340000',
|
||
serverpartId:this.serviceInfo.SERVERPART_NAME==='安徽驿达'?null:this.serviceInfo.Serverpart_ID,
|
||
statisticsMonth:this.$util.getThisMonth(time)
|
||
}
|
||
const data = await request.$webGet('CommercialApi/Customer/GetCustomerConsumeRatio',req)
|
||
let res = []
|
||
data.Result_Data.List.forEach(item=>{
|
||
res.push({name:item.name,big:(item.data[3]+item.data[2]).toFixed(2),normal:(item.data[1]).toFixed(2),small:item.data[0].toFixed(2)})
|
||
})
|
||
|
||
// let res=[{name:'男',big:'14.8',normal:'41.7',small:'43.5'},
|
||
// {name:'女',big:'44.1',normal:'31.7',small:'24.2'}]
|
||
this.consumptionLevelList = res
|
||
},
|
||
//业态偏好
|
||
async getBusinessTypeList(){
|
||
let time = ''
|
||
const date = new Date(this.single)
|
||
let y = date.getFullYear()
|
||
let m = date.getMonth() + 1
|
||
const nowDate = new Date(this.time)
|
||
let nowYear = nowDate.getFullYear()
|
||
let nowMonth = nowDate.getMonth() + 1
|
||
if (y===nowYear && m===nowMonth){
|
||
time = this.time
|
||
}else{
|
||
time = this.endTime
|
||
}
|
||
let req
|
||
if (this.serviceInfo.SERVERPART_NAME==='安徽驿达'){
|
||
req = {
|
||
ProvinceCode:'340000',
|
||
StatisticsDate:time,
|
||
}
|
||
}else{
|
||
req = {
|
||
ProvinceCode:'340000',
|
||
StatisticsDate:time,
|
||
serverpartId:this.serviceInfo.Serverpart_ID
|
||
}
|
||
}
|
||
const data = await request.$webGet('CommercialApi/Revenue/GetBusinessTradeRevenue',req)
|
||
let res = []
|
||
let all = 0
|
||
if (data.Result_Data){
|
||
data.Result_Data.BusinessTradeRank.forEach((item,index)=>{
|
||
if (index<=4){
|
||
res.push({name:`${item.name} ${item.value}%`,value:Number(item.value)})
|
||
all+=Number(item.value)
|
||
}else if(index===5){
|
||
if (all<100){
|
||
res.push({name:`其他${(100-all).toFixed(2)}%`,value:Number((100 - all).toFixed(2))})
|
||
}
|
||
}
|
||
})
|
||
let result = [
|
||
{
|
||
data:res
|
||
}
|
||
]
|
||
|
||
// let res=[
|
||
// {
|
||
// data: [{name:"餐饮 35.6%",value:35.6},
|
||
// {name:"小吃 22.5%",value:22.5},
|
||
// {name:"水果饮品 17.3%",value:17.3},
|
||
// {name:"粽子 15.2%",value:15.2},
|
||
// {name:"商超 5.8%",value:5.8},
|
||
// {name:"其他 3.6%",value:3.6}]
|
||
// }
|
||
// ]
|
||
this.businessTypeList = result
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.main{
|
||
width: 100vw;
|
||
min-height: 100vh;
|
||
.charts{
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
padding: 14px 16px 24px;
|
||
background: #fff;
|
||
.time{
|
||
margin-bottom: 4px;
|
||
.thisTime{
|
||
font-size: 14px;
|
||
font-family: PingFangSC-Semibold, PingFang SC;
|
||
font-weight: 500;
|
||
color: #160002;
|
||
}
|
||
.select{
|
||
margin-left: 8px;
|
||
display: inline-block;
|
||
.time {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-right: 4px;
|
||
.day {
|
||
font-size: 32rpx;
|
||
font-family: PingFangSC-Regular, PingFang SC;
|
||
font-weight: 400;
|
||
color: #782717;
|
||
line-height: 44rpx;
|
||
margin-right: 4px;
|
||
}
|
||
.uni-input {
|
||
font-size: 14px;
|
||
font-family: PingFangSC-Regular, PingFang SC;
|
||
font-weight: 400;
|
||
color: #ae664e;
|
||
line-height: 36rpx;
|
||
}
|
||
.icon {
|
||
width: 24px;
|
||
height: 16px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
.chartsItem{
|
||
.title{
|
||
font-size: 17px;
|
||
font-family: PingFangSC-Semibold, PingFang SC;
|
||
font-weight: 600;
|
||
color: #160002;
|
||
line-height: 24px;
|
||
}
|
||
.item{
|
||
.value{
|
||
font-size: 14px;
|
||
font-family: PingFangSC-Semibold, PingFang SC;
|
||
font-weight: 400;
|
||
color: #160002;
|
||
line-height: 20px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</style>
|