地图和组件加载速度 完善
This commit is contained in:
parent
528929f870
commit
bcc33a988a
@ -1,376 +1,553 @@
|
|||||||
<template>
|
<script setup lang="ts">
|
||||||
<view class="business-case">
|
import { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
||||||
<!-- 营收特征标题和Tab切换 -->
|
import SmallTitle from '../smallTitle/smallTitle.vue'
|
||||||
<view class="section-header">
|
import RevenueYOYIcon from '../../../../assets/image/RevenueYOYIcon.png'
|
||||||
<text class="section-title">营收特征</text>
|
import './BusinessCase.less'
|
||||||
<view class="tab-container">
|
import moment from 'moment';
|
||||||
<view v-for="(item, index) in tabList" :key="index"
|
import { handleCodeGetRevenueCompare, handleGetRevenueTrend } from '../../service';
|
||||||
:class="selectTab === item.value ? 'tab-item active-tab' : 'tab-item'"
|
import * as echarts from 'echarts/core';
|
||||||
@click="handleChangeTab(item.value)">
|
import { BarChart, LineChart } from 'echarts/charts';
|
||||||
{{ item.label }}
|
import {
|
||||||
</view>
|
GridComponent,
|
||||||
</view>
|
TitleComponent,
|
||||||
</view>
|
TooltipComponent,
|
||||||
|
LegendComponent,
|
||||||
|
DatasetComponent, // 必须添加!否则 dataset 功能无效
|
||||||
|
TransformComponent // 如果使用 dataset.source 需要此组件
|
||||||
|
} from 'echarts/components';
|
||||||
|
import { CanvasRenderer } from 'echarts/renderers';
|
||||||
|
import addIcon from '../../../../assets/image/addIcon.png'
|
||||||
|
import reduce from '../../../../assets/image/reduce.png'
|
||||||
|
|
||||||
<!-- 营收特征分析图表 -->
|
|
||||||
<view class="chart-container">
|
|
||||||
<QiunDataCharts type="column" :opts="chartOpts" :chartData="chartData" :canvas2d="true" :inScrollView="true"
|
|
||||||
canvasId="businessCaseChart" :animation="false" :ontap="true" :ontouch="true" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import QiunDataCharts from './qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue'
|
|
||||||
import request from "@/util/index.js";
|
|
||||||
import moment from 'moment'
|
|
||||||
|
|
||||||
export default {
|
// 注册组件
|
||||||
components: {
|
echarts.use([
|
||||||
QiunDataCharts
|
LineChart,
|
||||||
},
|
BarChart,
|
||||||
|
GridComponent,
|
||||||
|
TitleComponent,
|
||||||
|
TooltipComponent,
|
||||||
|
LegendComponent,
|
||||||
|
DatasetComponent, // 必须注册
|
||||||
|
TransformComponent, // 必须注册
|
||||||
|
CanvasRenderer
|
||||||
|
]);
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
let myChart: echarts.ECharts;
|
||||||
// Tab列表
|
let myChartBottom: echarts.ECharts;
|
||||||
tabList: [
|
|
||||||
|
const tabList: any = [
|
||||||
{ label: "营收金额", value: 1 },
|
{ label: "营收金额", value: 1 },
|
||||||
{ label: "客单量", value: 2 },
|
{ label: "客单量", value: 2 },
|
||||||
{ label: "客单均价", value: 3 }
|
{ label: "客单均价", value: 3 },
|
||||||
],
|
]
|
||||||
selectTab: 1, // 当前选中的Tab
|
let selectTab = ref<number>(1)
|
||||||
|
|
||||||
// 当前请求来的实际数据
|
|
||||||
realData: {},
|
|
||||||
|
|
||||||
// 图表原始数据
|
|
||||||
rawData: {
|
|
||||||
category: [],
|
|
||||||
seriesData: []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
// 当前请求来的实际数据
|
||||||
// 图表数据
|
let realData = ref<any>()
|
||||||
chartData() {
|
// 请求到的整个数据
|
||||||
return {
|
let getAllData = ref<any>()
|
||||||
categories: this.rawData.category,
|
|
||||||
series: this.rawData.seriesData
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// 图表配置
|
// 传入的数据
|
||||||
chartOpts() {
|
const props = defineProps<{
|
||||||
return {
|
currentService?: any;
|
||||||
padding: [15, 15, 40, 15],
|
selectTab?: any
|
||||||
dataLabel: false,
|
}>();
|
||||||
enableScroll: true,
|
|
||||||
xAxis: {
|
|
||||||
disableGrid: true,
|
|
||||||
itemCount: 4,
|
|
||||||
scrollShow: true,
|
|
||||||
scrollAlign: 'left',
|
|
||||||
scrollColor: '#46B8F3',
|
|
||||||
scrollWidth: 4,
|
|
||||||
scrollHeight: 8,
|
|
||||||
margin: 15
|
|
||||||
},
|
|
||||||
yAxis: {
|
|
||||||
data: [{
|
|
||||||
min: 0,
|
|
||||||
title: this.getYAxisTitle()
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
show: true,
|
|
||||||
position: 'bottom',
|
|
||||||
float: 'center',
|
|
||||||
backgroundColor: 'rgba(0,0,0,0)',
|
|
||||||
borderColor: 'rgba(0,0,0,0)',
|
|
||||||
fontSize: 12,
|
|
||||||
fontColor: '#333333',
|
|
||||||
margin: 0,
|
|
||||||
padding: 0,
|
|
||||||
itemGap: 10,
|
|
||||||
textAlign: 'left'
|
|
||||||
},
|
|
||||||
extra: {
|
|
||||||
column: {
|
|
||||||
type: 'group',
|
|
||||||
width: 12,
|
|
||||||
activeBgColor: '#000000',
|
|
||||||
activeBgOpacity: 0.08,
|
|
||||||
seriesGap: 0,
|
|
||||||
barBorderRadius: [3, 3, 0, 0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onReady() {
|
// 监听传入的选中服务区
|
||||||
this.handleGetBusinessCaseData()
|
watch(
|
||||||
|
() => props.currentService,
|
||||||
|
(newVal, oldVal) => {
|
||||||
|
handleGetData()
|
||||||
|
handleGetBottomData()
|
||||||
},
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
|
|
||||||
methods: {
|
// 监听传入的选中服务区
|
||||||
// 获取营收特征数据
|
watch(
|
||||||
async handleGetBusinessCaseData() {
|
() => props.selectTab,
|
||||||
const req = {
|
(newVal, oldVal) => {
|
||||||
|
handleShowData(newVal)
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
// 用tab可以修改的方法
|
||||||
|
await handleGetData()
|
||||||
|
// await handleGetBottomData()
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// 切换tab的内容
|
||||||
|
const handleChangeTab = async (value: number) => {
|
||||||
|
selectTab.value = value
|
||||||
|
handleShowData(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拿到数据的方法
|
||||||
|
const handleGetData = async () => {
|
||||||
|
const req: any = {
|
||||||
ProvinceCode: "530000",
|
ProvinceCode: "530000",
|
||||||
StatisticsDate: moment().subtract(1, 'd').format('YYYY-MM-DD'),
|
StatisticsDate: moment().subtract(1, 'd').format('YYYY-MM-DD'),
|
||||||
ServerpartId: "", // 暂时为空,如果需要传入服务区ID可以在这里添加
|
ServerpartId: props.currentService?.SERVERPART_ID || "",
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await this.getRevenueCompare(req);
|
let BusinessCase = sessionStorage.getItem('BusinessCase')
|
||||||
|
let data: any = []
|
||||||
|
if (BusinessCase) {
|
||||||
|
data = JSON.parse(BusinessCase)
|
||||||
|
} else {
|
||||||
|
data = await handleCodeGetRevenueCompare(req)
|
||||||
|
sessionStorage.setItem("BusinessCase", JSON.stringify(data))
|
||||||
|
}
|
||||||
|
|
||||||
// 处理数据
|
// const data = await handleCodeGetRevenueCompare(req)
|
||||||
this.processChartData(data)
|
|
||||||
},
|
|
||||||
|
|
||||||
// 发起API请求获取营收特征数据
|
getAllData.value = data
|
||||||
async getRevenueCompare(params) {
|
|
||||||
const data = await request.$webGet(
|
|
||||||
"CommercialApi/Revenue/GetCodeRevenueCompare",
|
|
||||||
params
|
|
||||||
);
|
|
||||||
console.log('营收特征数据', data);
|
|
||||||
return data || {}
|
|
||||||
},
|
|
||||||
|
|
||||||
// 处理图表数据
|
// 营收金额
|
||||||
processChartData(data) {
|
let category: any = ['product']
|
||||||
let monthList = []
|
let monthList: number[] = []
|
||||||
|
|
||||||
// 获取月份列表
|
|
||||||
let list = data.RevenueAmountList
|
let list = data.RevenueAmountList
|
||||||
if (list && list.length > 0) {
|
if (list && list.length > 0) {
|
||||||
list.forEach((item, index) => {
|
list.forEach((item: any, index: number) => {
|
||||||
|
category.push(item.name)
|
||||||
if (index === 0 && item.data && item.data.length > 0) {
|
if (index === 0 && item.data && item.data.length > 0) {
|
||||||
item.data.forEach((subItem) => {
|
item.data.forEach((subItem: any) => {
|
||||||
monthList.push(subItem[0])
|
monthList.push(subItem[0])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 营收金额数据
|
let aiObj1: any = {}
|
||||||
let revenueData = this.processRevenueAmount(data, monthList)
|
// 营收
|
||||||
|
let res: any = []
|
||||||
// 客单量数据
|
|
||||||
let ticketData = this.processTicketCount(data, monthList)
|
|
||||||
|
|
||||||
// 客单均价数据
|
|
||||||
let avgData = this.processAvgTicketAmount(data, monthList)
|
|
||||||
|
|
||||||
// 保存所有数据
|
|
||||||
this.realData = {
|
|
||||||
1: revenueData,
|
|
||||||
2: ticketData,
|
|
||||||
3: avgData
|
|
||||||
}
|
|
||||||
|
|
||||||
// 显示当前选中的数据
|
|
||||||
this.handleShowData(this.selectTab)
|
|
||||||
},
|
|
||||||
|
|
||||||
// 处理营收金额数据
|
|
||||||
processRevenueAmount(data, monthList) {
|
|
||||||
let category = []
|
|
||||||
let seriesData = []
|
|
||||||
|
|
||||||
let list = data.RevenueAmountList
|
|
||||||
if (list && list.length > 0) {
|
|
||||||
list.forEach((item) => {
|
|
||||||
let dataValues = []
|
|
||||||
if (monthList && monthList.length > 0) {
|
if (monthList && monthList.length > 0) {
|
||||||
monthList.forEach((month) => {
|
monthList.forEach((item: number) => {
|
||||||
let newData = item.data
|
let list: any = [`${item}月`]
|
||||||
dataValues.push(Number(((newData[month - 1][1]) / 10000).toFixed(2)))
|
data.RevenueAmountList.forEach((subItem: any) => {
|
||||||
})
|
let newData: any = subItem.data
|
||||||
}
|
list.push(Number(((newData[item - 1][1]) / 10000).toFixed(2)))
|
||||||
seriesData.push({
|
|
||||||
name: item.name,
|
|
||||||
data: dataValues
|
|
||||||
})
|
})
|
||||||
|
aiObj1[`${item}月`] = `工作日平均${list[1]}元,周末平均${list[2]}元,节假日平均${list[3]}元`
|
||||||
|
res.push(list)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 客单量
|
||||||
|
let res2: any = []
|
||||||
|
let aiObj2: any = {}
|
||||||
if (monthList && monthList.length > 0) {
|
if (monthList && monthList.length > 0) {
|
||||||
monthList.forEach((month) => {
|
monthList.forEach((item: number) => {
|
||||||
category.push(`${month}月`)
|
let list: any = [`${item}月`]
|
||||||
|
data.TicketCountList.forEach((subItem: any) => {
|
||||||
|
let newData: any = subItem.data
|
||||||
|
list.push(Number(((newData[item - 1][1]) / 10000).toFixed(2)))
|
||||||
|
})
|
||||||
|
aiObj2[`${item}月`] = `工作日平均${list[1]}元,周末平均${list[2]}元,节假日平均${list[3]}元`
|
||||||
|
res2.push(list)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return { category, seriesData }
|
// 均价
|
||||||
},
|
let res3: any = []
|
||||||
|
let aiObj3: any = {}
|
||||||
// 处理客单量数据
|
|
||||||
processTicketCount(data, monthList) {
|
|
||||||
let category = []
|
|
||||||
let seriesData = []
|
|
||||||
|
|
||||||
let list = data.TicketCountList
|
|
||||||
if (list && list.length > 0) {
|
|
||||||
list.forEach((item) => {
|
|
||||||
let dataValues = []
|
|
||||||
if (monthList && monthList.length > 0) {
|
if (monthList && monthList.length > 0) {
|
||||||
monthList.forEach((month) => {
|
monthList.forEach((item: number) => {
|
||||||
let newData = item.data
|
let list: any = [`${item}月`]
|
||||||
dataValues.push(Number(((newData[month - 1][1]) / 10000).toFixed(2)))
|
data.AvgTicketAmountList.forEach((subItem: any) => {
|
||||||
})
|
let newData: any = subItem.data
|
||||||
}
|
list.push(newData[item - 1][1])
|
||||||
seriesData.push({
|
|
||||||
name: item.name,
|
|
||||||
data: dataValues
|
|
||||||
})
|
})
|
||||||
|
aiObj3[`${item}月`] = `工作日平均${list[1]}元,周末平均${list[2]}元,节假日平均${list[3]}元`
|
||||||
|
res3.push(list)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (monthList && monthList.length > 0) {
|
|
||||||
monthList.forEach((month) => {
|
let obj: any = {
|
||||||
category.push(`${month}月`)
|
1: [category, ...res],
|
||||||
})
|
2: [category, ...res2],
|
||||||
|
3: [category, ...res3],
|
||||||
|
}
|
||||||
|
realData.value = obj
|
||||||
|
|
||||||
|
let BusinessCaseAI = sessionStorage.getItem('BusinessCaseAI')
|
||||||
|
if (BusinessCaseAI) { } else {
|
||||||
|
let aiObj: any = {
|
||||||
|
"营收金额": aiObj1,
|
||||||
|
"客单量": aiObj2,
|
||||||
|
"客单均价": aiObj3,
|
||||||
|
}
|
||||||
|
sessionStorage.setItem("BusinessCaseAI", JSON.stringify(aiObj))
|
||||||
}
|
}
|
||||||
|
|
||||||
return { category, seriesData }
|
handleShowData(selectTab.value)
|
||||||
},
|
|
||||||
|
|
||||||
// 处理客单均价数据
|
|
||||||
processAvgTicketAmount(data, monthList) {
|
|
||||||
let category = []
|
|
||||||
let seriesData = []
|
|
||||||
|
|
||||||
let list = data.AvgTicketAmountList
|
|
||||||
if (list && list.length > 0) {
|
|
||||||
list.forEach((item) => {
|
|
||||||
let dataValues = []
|
|
||||||
if (monthList && monthList.length > 0) {
|
|
||||||
monthList.forEach((month) => {
|
|
||||||
let newData = item.data
|
|
||||||
dataValues.push(Number(newData[month - 1][1]))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
seriesData.push({
|
|
||||||
name: item.name,
|
|
||||||
data: dataValues
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (monthList && monthList.length > 0) {
|
|
||||||
monthList.forEach((month) => {
|
|
||||||
category.push(`${month}月`)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return { category, seriesData }
|
|
||||||
},
|
|
||||||
|
|
||||||
// 切换显示的数据
|
|
||||||
handleShowData(tabValue) {
|
|
||||||
const data = this.realData[tabValue]
|
|
||||||
if (data) {
|
|
||||||
this.rawData = {
|
|
||||||
category: data.category,
|
|
||||||
seriesData: data.seriesData
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// 切换Tab
|
|
||||||
handleChangeTab(value) {
|
|
||||||
this.selectTab = value
|
|
||||||
this.handleShowData(value)
|
|
||||||
},
|
|
||||||
|
|
||||||
// 获取Y轴标题
|
|
||||||
getYAxisTitle() {
|
|
||||||
if (this.selectTab === 1) {
|
|
||||||
return '营收金额(万元)'
|
|
||||||
} else if (this.selectTab === 2) {
|
|
||||||
return '客单量(万笔)'
|
|
||||||
} else if (this.selectTab === 3) {
|
|
||||||
return '客单均价(元)'
|
|
||||||
}
|
|
||||||
return ''
|
|
||||||
},
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 拿到底部的方法
|
||||||
|
const handleGetBottomData = async () => {
|
||||||
|
const req: any = {
|
||||||
|
ProvinceCode: "530000",
|
||||||
|
StatisticsDate: moment().format('YYYY'),
|
||||||
|
StatisticsType: 1,
|
||||||
|
ServerpartId: props.currentService?.SERVERPART_ID || "",
|
||||||
|
}
|
||||||
|
const yesReq: any = {
|
||||||
|
ProvinceCode: "530000",
|
||||||
|
StatisticsDate: moment().subtract(1, 'y').format('YYYY'),
|
||||||
|
StatisticsType: 1,
|
||||||
|
ServerpartId: props.currentService?.SERVERPART_ID || "",
|
||||||
|
}
|
||||||
|
const data = await handleGetRevenueTrend(req)
|
||||||
|
const yesData = await handleGetRevenueTrend(yesReq)
|
||||||
|
|
||||||
|
|
||||||
|
let category: string[] = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
|
||||||
|
let currentYear: number[] = []
|
||||||
|
let lastYear: number[] = []
|
||||||
|
|
||||||
|
if (data && data.length > 0) {
|
||||||
|
data.forEach((item: any) => {
|
||||||
|
currentYear.push(Number((Number(item.value) / 10000).toFixed(2)))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (yesData && yesData.length > 0) {
|
||||||
|
yesData.forEach((item: any) => {
|
||||||
|
lastYear.push(Number((Number(item.value) / 10000).toFixed(2)))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
await handleShowBottomData({
|
||||||
|
category: category,
|
||||||
|
currentYear: currentYear,
|
||||||
|
lastYear: lastYear,
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 切换显示的数据源 营收特征分析的
|
||||||
|
const handleShowData = async (value: number) => {
|
||||||
|
let data = realData.value[value]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const chartDom = document.getElementById('featureAnalysis');
|
||||||
|
if (!chartDom) return;
|
||||||
|
|
||||||
|
myChart = echarts.init(chartDom);
|
||||||
|
|
||||||
|
const option = {
|
||||||
|
legend: {
|
||||||
|
top: 15,
|
||||||
|
right: 0,
|
||||||
|
textStyle: {
|
||||||
|
color: '#ffffff' // 设置图例文字为白色
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tooltip: { trigger: 'axis' },
|
||||||
|
dataset: { source: data },
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
axisLabel: {
|
||||||
|
width: '80',
|
||||||
|
interval: 0,
|
||||||
|
color: '#fff',
|
||||||
|
formatter: '{value}' // 刻度值保持纯数字
|
||||||
|
},
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#fff' // 设置 y 轴线颜色为白色(可选)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false // 隐藏刻度小线条
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
name: `${selectTab.value === 1 ? '营收金额(万元)' : selectTab.value === 2 ? '客单量(万笔)' : selectTab.value === 3 ? '客单均价(元)' : ''}`,
|
||||||
|
splitLine: { show: false }, // 隐藏网格线
|
||||||
|
axisLine: {
|
||||||
|
show: true, // 显示Y轴线
|
||||||
|
lineStyle: {
|
||||||
|
color: '#fff' // 轴线颜色
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false // 隐藏刻度线(短横线)
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
width: '80',
|
||||||
|
color: '#fff'
|
||||||
|
},
|
||||||
|
nameTextStyle: {
|
||||||
|
color: '#fff', // 名称颜色
|
||||||
|
padding: [0, 0, 35, 30] // 名称位置调整
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
type: 'bar',
|
||||||
|
itemStyle: {
|
||||||
|
color: '#0094FF' // 第一根柱子的颜色
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'bar',
|
||||||
|
itemStyle: {
|
||||||
|
color: '#69BCFF' // 第一根柱子的颜色
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'bar',
|
||||||
|
itemStyle: {
|
||||||
|
color: '#6B7C8B' // 第一根柱子的颜色
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
grid: {
|
||||||
|
left: '0', // 左侧间距
|
||||||
|
right: '0', // 右侧间距
|
||||||
|
bottom: '0', // 底部间距
|
||||||
|
top: '120', // 顶部间距
|
||||||
|
containLabel: true // 确保坐标轴标签在grid内
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
myChart.setOption(option);
|
||||||
|
window.addEventListener('resize', resizeChart);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 切换显示数据源 营收同比分析的
|
||||||
|
const handleShowBottomData = async (res: any) => {
|
||||||
|
|
||||||
|
const chartDom = document.getElementById('featureAnalysisBottom');
|
||||||
|
if (!chartDom) return;
|
||||||
|
myChartBottom = echarts.init(chartDom);
|
||||||
|
|
||||||
|
|
||||||
|
const option = {
|
||||||
|
legend: {
|
||||||
|
top: 10, // 距离容器底部距离
|
||||||
|
right: 0,
|
||||||
|
itemWidth: 20, // 图例标记的图形宽度
|
||||||
|
itemHeight: 10, // 图例标记的图形高度
|
||||||
|
textStyle: {
|
||||||
|
color: '#fff' // 图例文字颜色
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: res.category,
|
||||||
|
boundaryGap: true,
|
||||||
|
axisLabel: {
|
||||||
|
interval: 0,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#fff' // 设置 y 轴线颜色为白色(可选)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#fff' // 设置 y 轴线颜色为白色(可选)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false // 隐藏刻度小线条
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
name: `${selectTab.value === 1 ? '营收金额(万元)' : selectTab.value === 2 ? '客单量(万笔)' : selectTab.value === 3 ? '客单均价(元)' : ''}`,
|
||||||
|
type: 'value',
|
||||||
|
splitLine: { show: false },
|
||||||
|
axisLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#fff' // 设置 y 轴线颜色为白色(可选)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#fff',
|
||||||
|
},
|
||||||
|
nameTextStyle: {
|
||||||
|
color: '#fff', // 名称颜色
|
||||||
|
padding: [0, 0, 0, 20] // 名称位置调整
|
||||||
|
}
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '10', // 增加左侧空间
|
||||||
|
right: '10', // 增加右侧空间
|
||||||
|
bottom: '0',
|
||||||
|
top: '80',
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '今年',
|
||||||
|
data: res.currentYear,
|
||||||
|
type: 'line',
|
||||||
|
lineStyle: {
|
||||||
|
width: 2,
|
||||||
|
color: '#0094FF'
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
color: '#0094FF'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '去年',
|
||||||
|
data: res.lastYear,
|
||||||
|
type: 'line',
|
||||||
|
lineStyle: {
|
||||||
|
width: 2,
|
||||||
|
color: '#00FFB7' // 改为橙色
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
color: '#00FFB7' // 改为橙色
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'line' // 改为线条指示器
|
||||||
|
},
|
||||||
|
formatter: function (params: any) {
|
||||||
|
return `${params.map((item: any) => {
|
||||||
|
return `<div>
|
||||||
|
${item.seriesName}:${item.value}万元
|
||||||
|
</div>`
|
||||||
|
}).join("")}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
myChartBottom.setOption(option);
|
||||||
|
window.addEventListener('resize', resizeChartBottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
const resizeChart = () => {
|
||||||
|
myChart?.resize();
|
||||||
|
};
|
||||||
|
const resizeChartBottom = () => {
|
||||||
|
myChart?.resize();
|
||||||
|
};
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
window.removeEventListener('resize', resizeChart);
|
||||||
|
myChart?.dispose();
|
||||||
|
|
||||||
|
|
||||||
|
window.removeEventListener('resize', resizeChartBottom);
|
||||||
|
myChartBottom?.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
handleGetData
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
|
||||||
@primary-color: #46B8F3;
|
|
||||||
@secondary-color: #3CD495;
|
|
||||||
@danger-color: #FF5E5E;
|
|
||||||
@success-color: #52C41A;
|
|
||||||
@text-primary: #333;
|
|
||||||
@text-secondary: #666;
|
|
||||||
@text-light: #999;
|
|
||||||
@bg-white: #ffffff;
|
|
||||||
@border-radius: 16rpx;
|
|
||||||
@shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
|
|
||||||
|
|
||||||
.business-case {
|
|
||||||
margin-top: 24rpx;
|
|
||||||
|
|
||||||
.section-header {
|
<template>
|
||||||
display: flex;
|
<div class="BusinessCaseBox">
|
||||||
align-items: center;
|
<div class="BusinessCaseBoxContent">
|
||||||
justify-content: space-between;
|
<SmallTitle title="营收特征">
|
||||||
margin-bottom: 20rpx;
|
<!-- <template #extra>
|
||||||
padding: 0 8rpx;
|
<div class="BusinessCaseTabBox">
|
||||||
|
<div :class="selectTab === item.value ? 'BusinessCaseItem selectBusinessCaseItem' : 'BusinessCaseItem'"
|
||||||
|
v-for="(item, index) in tabList" :key="index" @click="handleChangeTab(item.value)">
|
||||||
|
{{ item.label }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template> -->
|
||||||
|
</SmallTitle>
|
||||||
|
</div>
|
||||||
|
|
||||||
.section-title {
|
|
||||||
font-size: 30rpx;
|
|
||||||
font-weight: 600;
|
|
||||||
color: @text-primary;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab-container {
|
<!-- 营收同比 -->
|
||||||
display: inline-flex;
|
<div class="BusinessCaseRevenueYOY" v-if="false">
|
||||||
align-items: center;
|
<div class="BusinessCaseLeftItem">
|
||||||
background: linear-gradient(90deg, rgba(0, 148, 255, 0.1) 0%, rgba(0, 148, 255, 0) 100%);
|
<img class="BusinessIcon" :src="RevenueYOYIcon" />
|
||||||
padding: 6rpx 40rpx;
|
</div>
|
||||||
box-sizing: border-box;
|
|
||||||
border-radius: 20rpx;
|
|
||||||
|
|
||||||
.tab-item {
|
<div class="BusinessCaseRightItem">
|
||||||
font-size: 30rpx;
|
<div class="BusinessCaseRightItemTop">
|
||||||
color: @text-secondary;
|
<div class="rightItemTitle">营收同比</div>
|
||||||
margin: 0 20rpx;
|
<div class="rightItemUpdate">{{ moment().subtract(1, 'd').format('YYYY-MM-DD') }}</div>
|
||||||
cursor: pointer;
|
</div>
|
||||||
transition: all 0.3s ease;
|
<div class="BusinessCaseRightItemBottom">
|
||||||
position: relative;
|
<div class="BusinessCaseItemBottomLeft">
|
||||||
|
<div class="changeBox">
|
||||||
|
<img v-if="getAllData?.RevenueAmountYOYRate || getAllData?.TicketCountYOYRate || getAllData?.AvgTicketAmountRate"
|
||||||
|
class="changeIcon" :src="selectTab === 1 ? getAllData?.RevenueAmountYOYRate > 0 ? addIcon : reduce :
|
||||||
|
selectTab === 2 ? getAllData?.TicketCountYOYRate > 0 ? addIcon : reduce :
|
||||||
|
selectTab === 3 ? getAllData?.AvgTicketAmountRate > 0 ? addIcon : reduce : ''
|
||||||
|
" />
|
||||||
|
<div class="changeText" :style="{
|
||||||
|
color: selectTab === 1 ? getAllData?.RevenueAmountYOYRate > 0 ? '#00FF00' : '#D24343' :
|
||||||
|
selectTab === 2 ? getAllData?.TicketCountYOYRate > 0 ? '#00FF00' : '#D24343' :
|
||||||
|
selectTab === 3 ? getAllData?.AvgTicketAmountRate > 0 ? '#00FF00' : '#D24343' : ''
|
||||||
|
}">{{
|
||||||
|
selectTab === 1 ? getAllData?.RevenueAmountYOYRate || '-' :
|
||||||
|
selectTab === 2 ? getAllData?.TicketCountYOYRate || '-' :
|
||||||
|
selectTab === 3 ? getAllData?.AvgTicketAmountRate || '-' : ''
|
||||||
|
}}%</div>
|
||||||
|
<div class="compareTitle">(相比去年同日)</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
&.active-tab {
|
<div class="BusinessCaseItemBottomRight">
|
||||||
color: @text-primary;
|
<div class="BusinessCaseRevenueValue">{{ selectTab === 1 ?
|
||||||
font-weight: 600;
|
getAllData?.RevenueAmount.toLocaleString() :
|
||||||
|
selectTab
|
||||||
|
=== 2 ?
|
||||||
|
getAllData?.TicketCount.toLocaleString() : selectTab === 3 ?
|
||||||
|
getAllData?.AvgTicketAmount.toLocaleString() : ''
|
||||||
|
}}</div>
|
||||||
|
<div class="BusinessCaseRevenueUnit">{{ selectTab === 2 ? '笔' : '元' }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
&::after {
|
<!-- <div class="rightItemLeft">
|
||||||
content: "";
|
<div class="rightItemTitleBox">
|
||||||
width: 100%;
|
<div class="rightItemTitle">营收同比</div>
|
||||||
height: 2rpx;
|
<div class="rightItemUpdate">{{ moment().subtract(1, 'd').format('YYYY-MM-DD') }}</div>
|
||||||
background: linear-gradient(180deg, #00F6FF 0%, #008CFF 100%);
|
</div>
|
||||||
position: absolute;
|
<div class="rightItemBottom">
|
||||||
left: 0;
|
<div class="compareTitle">相比去年同日</div>
|
||||||
bottom: -8rpx;
|
<div class="changeBox">
|
||||||
}
|
<img class="changeIcon" />
|
||||||
}
|
<div class="changeText"></div>
|
||||||
}
|
</div>
|
||||||
}
|
</div>
|
||||||
}
|
</div> -->
|
||||||
|
|
||||||
.chart-container {
|
<!-- <div class="rightItemRight">
|
||||||
background: @bg-white;
|
<div class="BusinessCaseRevenueValue"></div>
|
||||||
border-radius: @border-radius;
|
<div class="BusinessCaseRevenueUnit">元</div>
|
||||||
padding: 24rpx;
|
</div> -->
|
||||||
box-shadow: @shadow;
|
</div>
|
||||||
margin-bottom: 24rpx;
|
</div>
|
||||||
width: 100%;
|
|
||||||
box-sizing: border-box;
|
<!-- 营收特征分析 -->
|
||||||
height: 400rpx;
|
<div class="featureAnalysis">
|
||||||
}
|
<!-- <SmallTitle title="营收特征分析" /> -->
|
||||||
}
|
|
||||||
</style>
|
<div class="featureAnalysisBox" id="featureAnalysis"></div>
|
||||||
|
|
||||||
|
<!-- <SmallTitle title="营收同比分析" style="margin-top: 31px;" />
|
||||||
|
|
||||||
|
<div class="featureAnalysisBottom" id="featureAnalysisBottom"></div> -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@ -67,6 +67,30 @@ onMounted(async () => {
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 🎯 监听地图加载完成事件
|
||||||
|
scene.value.on('loaded', () => {
|
||||||
|
console.log('🗺️ L7场景加载完成')
|
||||||
|
|
||||||
|
// 🔄 智能布局稳定检测 - 不依赖固定时间
|
||||||
|
handleDetectLayoutStability()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 🎯 监听容器可见性变化(处理v-show切换)
|
||||||
|
const observer = new IntersectionObserver((entries) => {
|
||||||
|
entries.forEach(entry => {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
console.log('🔄 地图容器变为可见 - 重新检测布局稳定性')
|
||||||
|
// 重新开始布局稳定性检测
|
||||||
|
handleDetectLayoutStability()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, { threshold: 0.1 })
|
||||||
|
|
||||||
|
const mapContainer = document.getElementById('map')
|
||||||
|
if (mapContainer) {
|
||||||
|
observer.observe(mapContainer)
|
||||||
|
}
|
||||||
|
|
||||||
// 请求全部服务区数据
|
// 请求全部服务区数据
|
||||||
await handleGetServiceList()
|
await handleGetServiceList()
|
||||||
|
|
||||||
@ -383,11 +407,64 @@ const handleLayerToDefault = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 🔄 智能布局稳定检测
|
||||||
|
const handleDetectLayoutStability = () => {
|
||||||
|
const mapContainer = document.getElementById('map')
|
||||||
|
if (!mapContainer) {
|
||||||
|
console.warn('地图容器未找到')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let lastWidth = 0
|
||||||
|
let stableCount = 0
|
||||||
|
const stabilityThreshold = 3 // 连续3次尺寸不变认为稳定
|
||||||
|
const checkInterval = 50 // 每50ms检查一次
|
||||||
|
|
||||||
|
console.log('🔍 开始监听地图容器尺寸变化...')
|
||||||
|
|
||||||
|
const checkSize = () => {
|
||||||
|
const currentWidth = mapContainer.offsetWidth
|
||||||
|
|
||||||
|
// 🎯 检查容器是否可见(处理v-show切换的情况)
|
||||||
|
if (currentWidth === 0) {
|
||||||
|
// 容器宽度为0,说明可能是隐藏状态,继续等待
|
||||||
|
setTimeout(checkSize, checkInterval)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentWidth === lastWidth) {
|
||||||
|
stableCount++
|
||||||
|
console.log(`尺寸稳定第 ${stableCount} 次,当前宽度: ${currentWidth}px`)
|
||||||
|
|
||||||
|
if (stableCount >= stabilityThreshold) {
|
||||||
|
console.log('✅ 地图布局已稳定 - 发射mapLoaded事件')
|
||||||
|
// 🎯 确保地图在重新显示时正确调整大小
|
||||||
|
if (scene.value) {
|
||||||
|
scene.value.render()
|
||||||
|
}
|
||||||
|
emit('mapLoaded')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stableCount = 0
|
||||||
|
console.log(`尺寸发生变化: ${lastWidth}px → ${currentWidth}px`)
|
||||||
|
lastWidth = currentWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
// 继续检查
|
||||||
|
setTimeout(checkSize, checkInterval)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始检查
|
||||||
|
checkSize()
|
||||||
|
}
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: "handleGetCurrentService", obj: any): void;
|
(e: "handleGetCurrentService", obj: any): void;
|
||||||
(e: "handleMapToChangeNotice"): void;
|
(e: "handleMapToChangeNotice"): void;
|
||||||
(e: "handleGetMapLegend", list: any): void;
|
(e: "handleGetMapLegend", list: any): void;
|
||||||
(e: "handleChangeComeForm", str: string): void;
|
(e: "handleChangeComeForm", str: string): void;
|
||||||
|
(e: "mapLoaded"): void; // 🎯 地图加载完成事件
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -41,7 +41,10 @@ const props = defineProps<{
|
|||||||
watch(
|
watch(
|
||||||
() => props.currentService,
|
() => props.currentService,
|
||||||
(newVal, oldVal) => {
|
(newVal, oldVal) => {
|
||||||
|
// 🎯 延迟重新初始化图表,避免在布局不稳定时触发
|
||||||
|
setTimeout(() => {
|
||||||
handleGoMounted()
|
handleGoMounted()
|
||||||
|
}, 100) // 延迟100ms,给布局稳定时间
|
||||||
},
|
},
|
||||||
{ deep: true }
|
{ deep: true }
|
||||||
);
|
);
|
||||||
|
|||||||
@ -41,7 +41,10 @@ const props = defineProps<{
|
|||||||
watch(
|
watch(
|
||||||
() => props.currentService,
|
() => props.currentService,
|
||||||
(newVal, oldVal) => {
|
(newVal, oldVal) => {
|
||||||
|
// 🎯 延迟重新初始化图表,避免在布局不稳定时触发
|
||||||
|
setTimeout(() => {
|
||||||
handleGoMounted()
|
handleGoMounted()
|
||||||
|
}, 100) // 延迟100ms,给布局稳定时间
|
||||||
},
|
},
|
||||||
{ deep: true }
|
{ deep: true }
|
||||||
);
|
);
|
||||||
@ -49,27 +52,41 @@ watch(
|
|||||||
// 初始运行的方法
|
// 初始运行的方法
|
||||||
const handleGoMounted = async () => {
|
const handleGoMounted = async () => {
|
||||||
const res: any = await handleGetSectionFlowCount()
|
const res: any = await handleGetSectionFlowCount()
|
||||||
|
|
||||||
|
// 🎯 确保容器有正确的尺寸再初始化图表
|
||||||
|
const initChartsWithDelay = () => {
|
||||||
const chartDom = document.getElementById('VehiclesEntering');
|
const chartDom = document.getElementById('VehiclesEntering');
|
||||||
if (!chartDom) return;
|
|
||||||
myChart = echarts.init(chartDom);
|
|
||||||
|
|
||||||
const chartDom2 = document.getElementById('TrendCustomerRevenue');
|
const chartDom2 = document.getElementById('TrendCustomerRevenue');
|
||||||
if (!chartDom2) return;
|
|
||||||
myChart2 = echarts.init(chartDom2);
|
|
||||||
|
|
||||||
|
if (!chartDom || !chartDom2) return;
|
||||||
|
|
||||||
|
// 🎯 检查容器是否可见且有正确尺寸
|
||||||
|
const containerRect = chartDom.getBoundingClientRect();
|
||||||
|
if (containerRect.width === 0 || containerRect.height === 0) {
|
||||||
|
// 如果容器还没有正确尺寸,稍后重试
|
||||||
|
setTimeout(initChartsWithDelay, 50);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
myChart = echarts.init(chartDom);
|
||||||
|
myChart2 = echarts.init(chartDom2);
|
||||||
|
|
||||||
const option = handleSetConfig(res)
|
const option = handleSetConfig(res)
|
||||||
const option2 = handleSetConfig2(res)
|
const option2 = handleSetConfig2(res)
|
||||||
|
|
||||||
|
|
||||||
myChart.setOption(option);
|
myChart.setOption(option);
|
||||||
myChart2.setOption(option2);
|
myChart2.setOption(option2);
|
||||||
|
|
||||||
myChart.resize();
|
// 🎯 移除多余的resize调用,避免在有缓存时布局计算冲突
|
||||||
myChart2.resize();
|
// myChart.resize();
|
||||||
|
// myChart2.resize();
|
||||||
|
|
||||||
window.addEventListener('resize', resizeChart);
|
window.addEventListener('resize', resizeChart);
|
||||||
window.addEventListener('resize', resizeChart2);
|
window.addEventListener('resize', resizeChart2);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 稍微延迟初始化,确保DOM已经稳定
|
||||||
|
setTimeout(initChartsWithDelay, 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSetConfig = (res: any) => {
|
const handleSetConfig = (res: any) => {
|
||||||
|
|||||||
@ -1,71 +1,66 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import './style.less'
|
import './style.less'
|
||||||
|
import { defineAsyncComponent, onMounted, ref } from 'vue';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
import moment from 'moment';
|
||||||
|
|
||||||
|
// 🚀 P0 - 立即加载的核心组件 (地图优先策略)
|
||||||
import PageTop from './components/pageTop/pageTop.vue'
|
import PageTop from './components/pageTop/pageTop.vue'
|
||||||
import modalTitle from './components/modalTitle/modalTitle.vue';
|
|
||||||
import TrendOfTrafficFlow from './components/TrendOfTrafficFlow/TrendOfTrafficFlow.vue'
|
|
||||||
import VehiclesEntering from './components/VehiclesEntering/VehiclesEntering.vue'
|
|
||||||
import PassengerFlowChanges from './components/PassengerFlowChanges/PassengerFlowChanges.vue'
|
|
||||||
import MultiIndustryIncome from './components/MultiIndustryIncome/MultiIndustryIncome.vue'
|
|
||||||
import BusinessStructure from './components/BusinessStructure/BusinessStructure.vue'
|
|
||||||
import CustomerAgeGroup from './components/CustomerAgeGroup/CustomerAgeGroup.vue'
|
|
||||||
import GenderCustomerGroup from './components/GenderCustomerGroup/GenderCustomerGroup.vue'
|
|
||||||
import CustomerGroupStay from './components/CustomerGroupStay/CustomerGroupStay.vue'
|
|
||||||
import PreferenceType from './components/PreferenceType/PreferenceType.vue'
|
|
||||||
import CoreBusinessData from './components/CoreBusinessData/CoreBusinessData.vue'
|
import CoreBusinessData from './components/CoreBusinessData/CoreBusinessData.vue'
|
||||||
import AnnouncementTopic from './components/AnnouncementTopic/AnnouncementTopic.vue'
|
import PageMap from './components/PageMap/PageMap.vue' // 地图同步加载,保持渲染
|
||||||
import MallOrderStatistics from './components/MallOrderStatistics/MallOrderStatistics.vue'
|
import AreaLegend from './components/AreaLegend/AreaLegend.vue';
|
||||||
import SalesComparison from './components/SalesComparison/SalesComparison.vue'
|
|
||||||
import ReturnRate from './components/ReturnRate/ReturnRate.vue';
|
|
||||||
import HotProductList from './components/HotProductList/HotProductList.vue'
|
|
||||||
import TodayTrend from './components/TodayTrend/TodayTrend.vue'
|
|
||||||
import TradingAlert from './components/TradingAlert/TradingAlert.vue'
|
|
||||||
import PrivateRideService from './components/PrivateRideService/PrivateRideService.vue'
|
|
||||||
import RegionalRevenue from './components/RegionalRevenue/RegionalRevenue.vue'
|
|
||||||
import PageMap from './components/PageMap/PageMap.vue'
|
|
||||||
import { onMounted, ref } from 'vue';
|
|
||||||
import FestivalRevenue from './components/FestivalRevenue/FestivalRevenue.vue';
|
|
||||||
import ConsumptionConversion from './components/ConsumptionConversion/ConsumptionConversion.vue'
|
|
||||||
import ConsumptionLevel from './components/ConsumptionLevel/ConsumptionLevel.vue';
|
|
||||||
import BrandConsumptionLevel from './components/BrandConsumptionLevel/BrandConsumptionLevel.vue';
|
|
||||||
import ConsumptionPeriod from './components/ConsumptionPeriod/ConsumptionPeriod.vue';
|
|
||||||
import PaymentProgress from './components/PaymentProgress/PaymentProgress.vue';
|
|
||||||
import TotalAccountsReceivable from './components/TotalAccountsReceivable/TotalAccountsReceivable.vue'
|
|
||||||
import AccountsReceivableWarning from './components/AccountsReceivableWarning/AccountsReceivableWarning.vue';
|
|
||||||
import BusyTradingRanking from './components/BusyTradingRanking/BusyTradingRanking.vue';
|
|
||||||
import NoticeListBox from './components/noticeListBox/noticeListBox.vue';
|
|
||||||
import BasicMessageBox from './components/BasicMessageBox/BasicMessageBox.vue';
|
|
||||||
import SupplierListBox from './components/supplierListBox/supplierListBox.vue'
|
|
||||||
import BrandListtBox from './components/BrandListtBox/BrandListtBox.vue';
|
|
||||||
import MerchantCategory from './components/MerchantCategory/MerchantCategory.vue';
|
|
||||||
import DeductionType from './components/DeductionType/DeductionType.vue';
|
|
||||||
import MerchantRatingRanking from './components/MerchantRatingRanking/MerchantRatingRanking.vue'
|
|
||||||
import HighQualityMerchants from './components/HighQualityMerchants/HighQualityMerchants.vue'
|
|
||||||
import ThisMonthBenefits from './components/ThisMonthBenefits/ThisMonthBenefits.vue';
|
|
||||||
import CoreCategory from './components/CoreCategory/CoreCategory.vue'
|
|
||||||
import BusinessCase from './components/BusinessCase/BusinessCase.vue'
|
|
||||||
import CustomerGroup from './components/CustomerGroup/CustomerGroup.vue'
|
|
||||||
import CustomerConsumptionPreferences from './components/CustomerConsumptionPreferences/CustomerConsumptionPreferences.vue'
|
|
||||||
import VehicleStayAnalysis from './components/VehicleStayAnalysis/VehicleStayAnalysis.vue'
|
|
||||||
import BrandDetail from './components/BrandDetail/BrandDetail.vue'
|
|
||||||
import AssessmentScoring from './components/AssessmentScoring/AssessmentScoring.vue';
|
|
||||||
import OverviewOfServiceArea from './components/OverviewOfServiceArea/OverviewOfServiceArea.vue'
|
|
||||||
import NewBigTitleBox from './components/newBigTitleBox/newBigTitleBox.vue'
|
import NewBigTitleBox from './components/newBigTitleBox/newBigTitleBox.vue'
|
||||||
import VehicleModelStay from './components/VehicleModelStay/VehicleModelStay.vue';
|
|
||||||
import ContractInformation from './components/ContractInformation/ContractInformation.vue'
|
// 🎯 P1 - 第一批异步组件 (200ms后显示) - 基础设施组件
|
||||||
import SignedClients from './components/SignedClients/SignedClients.vue'
|
const NoticeListBox = defineAsyncComponent(() => import('./components/noticeListBox/noticeListBox.vue'))
|
||||||
import AnnualAccountsReceivable from './components/AnnualAccountsReceivable/AnnualAccountsReceivable.vue';
|
const BasicMessageBox = defineAsyncComponent(() => import('./components/BasicMessageBox/BasicMessageBox.vue'))
|
||||||
import DetailedPayment from './components/DetailedPayment/DetailedPayment.vue';
|
const OverviewOfServiceArea = defineAsyncComponent(() => import('./components/OverviewOfServiceArea/OverviewOfServiceArea.vue'))
|
||||||
import DailyInspection from './components/DailyInspection/DailyInspection.vue';
|
const TradingAlert = defineAsyncComponent(() => import('./components/TradingAlert/TradingAlert.vue'))
|
||||||
import AssessmentScoringRanking from './components/AssessmentScoringRanking/AssessmentScoringRanking.vue';
|
const modalTitle = defineAsyncComponent(() => import('./components/modalTitle/modalTitle.vue'))
|
||||||
import SmallTitle from './components/smallTitle/smallTitle.vue';
|
const VehicleModelStay = defineAsyncComponent(() => import('./components/VehicleModelStay/VehicleModelStay.vue'))
|
||||||
import FestivalRevenueSumInfo from './components/FestivalRevenueSumInfo/FestivalRevenueSumInfo.vue'
|
|
||||||
|
// 📊 P2 - 第二批异步组件 (600ms后显示) - 数据分析组件
|
||||||
|
const TrendOfTrafficFlow = defineAsyncComponent(() => import('./components/TrendOfTrafficFlow/TrendOfTrafficFlow.vue'))
|
||||||
|
const VehiclesEntering = defineAsyncComponent(() => import('./components/VehiclesEntering/VehiclesEntering.vue'))
|
||||||
|
const FestivalRevenueSumInfo = defineAsyncComponent(() => import('./components/FestivalRevenueSumInfo/FestivalRevenueSumInfo.vue'))
|
||||||
|
const RegionalRevenue = defineAsyncComponent(() => import('./components/RegionalRevenue/RegionalRevenue.vue'))
|
||||||
|
const BusinessStructure = defineAsyncComponent(() => import('./components/BusinessStructure/BusinessStructure.vue'))
|
||||||
|
|
||||||
|
// 👥 P3 - 第三批异步组件 (1200ms后显示) - 用户分析组件
|
||||||
|
const CustomerAgeGroup = defineAsyncComponent(() => import('./components/CustomerAgeGroup/CustomerAgeGroup.vue'))
|
||||||
|
const GenderCustomerGroup = defineAsyncComponent(() => import('./components/GenderCustomerGroup/GenderCustomerGroup.vue'))
|
||||||
|
const PreferenceType = defineAsyncComponent(() => import('./components/PreferenceType/PreferenceType.vue'))
|
||||||
|
const CustomerGroup = defineAsyncComponent(() => import('./components/CustomerGroup/CustomerGroup.vue'))
|
||||||
|
const CustomerConsumptionPreferences = defineAsyncComponent(() => import('./components/CustomerConsumptionPreferences/CustomerConsumptionPreferences.vue'))
|
||||||
|
const ConsumptionConversion = defineAsyncComponent(() => import('./components/ConsumptionConversion/ConsumptionConversion.vue'))
|
||||||
|
const ConsumptionLevel = defineAsyncComponent(() => import('./components/ConsumptionLevel/ConsumptionLevel.vue'))
|
||||||
|
const ConsumptionPeriod = defineAsyncComponent(() => import('./components/ConsumptionPeriod/ConsumptionPeriod.vue'))
|
||||||
|
const BrandConsumptionLevel = defineAsyncComponent(() => import('./components/BrandConsumptionLevel/BrandConsumptionLevel.vue'))
|
||||||
|
const BusinessCase = defineAsyncComponent(() => import('./components/BusinessCase/BusinessCase.vue'))
|
||||||
|
|
||||||
|
// 🏢 P4 - 第四批异步组件 (1800ms后显示) - 业务管理组件
|
||||||
|
const BrandDetail = defineAsyncComponent(() => import('./components/BrandDetail/BrandDetail.vue'))
|
||||||
|
const SupplierListBox = defineAsyncComponent(() => import('./components/supplierListBox/supplierListBox.vue'))
|
||||||
|
const MallOrderStatistics = defineAsyncComponent(() => import('./components/MallOrderStatistics/MallOrderStatistics.vue'))
|
||||||
|
const ThisMonthBenefits = defineAsyncComponent(() => import('./components/ThisMonthBenefits/ThisMonthBenefits.vue'))
|
||||||
|
const MemberMall = defineAsyncComponent(() => import('./components/MemberMall/index.vue'))
|
||||||
|
const AnalysisOfMember = defineAsyncComponent(() => import('./components/AnalysisOfMember/AnalysisOfMember.vue'))
|
||||||
|
|
||||||
|
// 📋 P5 - 第五批异步组件 (2400ms后显示) - 其他组件
|
||||||
|
const HotProductList = defineAsyncComponent(() => import('./components/HotProductList/HotProductList.vue'))
|
||||||
|
const MerchantCategory = defineAsyncComponent(() => import('./components/MerchantCategory/MerchantCategory.vue'))
|
||||||
|
const CoreCategory = defineAsyncComponent(() => import('./components/CoreCategory/CoreCategory.vue'))
|
||||||
|
|
||||||
|
// 🚫 暂时隐藏的组件 (v-if="false" 的组件不导入)
|
||||||
|
// PassengerFlowChanges, MultiIndustryIncome, AnnouncementTopic, SalesComparison, ReturnRate
|
||||||
|
// TodayTrend, PrivateRideService, FestivalRevenue, PaymentProgress, TotalAccountsReceivable
|
||||||
|
// AccountsReceivableWarning, BusyTradingRanking, BrandListtBox, DeductionType, MerchantRatingRanking
|
||||||
|
// HighQualityMerchants, VehicleStayAnalysis, AssessmentScoring, ContractInformation, SignedClients
|
||||||
|
// AnnualAccountsReceivable, DetailedPayment, DailyInspection, AssessmentScoringRanking
|
||||||
|
|
||||||
|
// 资源文件
|
||||||
import AIIcon from '../../assets/image/AIIcon.png'
|
import AIIcon from '../../assets/image/AIIcon.png'
|
||||||
import showMapIcon from '../../assets/image/showMapIcon.png'
|
import showMapIcon from '../../assets/image/showMapIcon.png'
|
||||||
import MemberMall from './components/MemberMall/index.vue'
|
|
||||||
import AnalysisOfMember from './components/AnalysisOfMember/AnalysisOfMember.vue'
|
|
||||||
import AreaLegend from './components/AreaLegend/AreaLegend.vue';
|
|
||||||
import { useRouter } from 'vue-router'; // 新增
|
|
||||||
import moment from 'moment';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -113,6 +108,16 @@ let mapClickComeForm = ref<string>("")
|
|||||||
// 当前招商信息的枚举
|
// 当前招商信息的枚举
|
||||||
let noticeMessageObj = ref<any>()
|
let noticeMessageObj = ref<any>()
|
||||||
|
|
||||||
|
// 🚀 分批显示控制变量 (地图优先策略)
|
||||||
|
const showBatch1 = ref<boolean>(false) // P1: 200ms后显示
|
||||||
|
const showBatch2 = ref<boolean>(false) // P2: 600ms后显示
|
||||||
|
const showBatch3 = ref<boolean>(false) // P3: 1200ms后显示
|
||||||
|
const showBatch4 = ref<boolean>(false) // P4: 1800ms后显示
|
||||||
|
const showBatch5 = ref<boolean>(false) // P5: 2400ms后显示
|
||||||
|
|
||||||
|
// 🎯 地图加载状态控制 (关键优化)
|
||||||
|
const mapLoaded = ref<boolean>(false) // 地图是否已完全加载并稳定
|
||||||
|
|
||||||
// 创建组件实例
|
// 创建组件实例
|
||||||
// 服务区概况
|
// 服务区概况
|
||||||
const OverviewOfServiceAreaRef = ref<any>()
|
const OverviewOfServiceAreaRef = ref<any>()
|
||||||
@ -170,6 +175,37 @@ onMounted(() => {
|
|||||||
router.push('/login')
|
router.push('/login')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 🚀 启动分批显示定时器 (地图优先策略)
|
||||||
|
setTimeout(() => {
|
||||||
|
showBatch1.value = true
|
||||||
|
// 📊 P1 批次数据获取 - 基础设施数据
|
||||||
|
handleGetBatch1Data()
|
||||||
|
}, 200) // P1: 200ms后显示基础组件
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
showBatch2.value = true
|
||||||
|
// 📈 P2 批次数据获取 - 流量趋势数据
|
||||||
|
handleGetBatch2Data()
|
||||||
|
}, 600) // P2: 600ms后显示数据组件
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
showBatch3.value = true
|
||||||
|
// 👥 P3 批次数据获取 - 用户分析数据
|
||||||
|
handleGetBatch3Data()
|
||||||
|
}, 1200) // P3: 1200ms后显示用户分析组件
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
showBatch4.value = true
|
||||||
|
// 🏢 P4 批次数据获取 - 业务管理数据
|
||||||
|
handleGetBatch4Data()
|
||||||
|
}, 1800) // P4: 1800ms后显示业务管理组件
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
showBatch5.value = true
|
||||||
|
// 📋 P5 批次数据获取 - 其他组件数据
|
||||||
|
handleGetBatch5Data()
|
||||||
|
}, 2400) // P5: 2400ms后显示其他组件
|
||||||
|
|
||||||
// 先判断当前是否已经存在了 之前的整点数据
|
// 先判断当前是否已经存在了 之前的整点数据
|
||||||
let integralPoint: string = sessionStorage.getItem('integralPoint') || ""
|
let integralPoint: string = sessionStorage.getItem('integralPoint') || ""
|
||||||
console.log('integralPointintegralPoint', integralPoint);
|
console.log('integralPointintegralPoint', integralPoint);
|
||||||
@ -191,6 +227,26 @@ onMounted(() => {
|
|||||||
let time: string = nowTime + ':00:00'
|
let time: string = nowTime + ':00:00'
|
||||||
sessionStorage.setItem('integralPoint', time)
|
sessionStorage.setItem('integralPoint', time)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 🚀 优化:首次页面加载时的智能数据获取策略
|
||||||
|
// 只加载当前显示tab的数据,避免加载所有tab的数据造成性能浪费
|
||||||
|
console.log('🎯 智能数据加载策略 - 当前Tab:', selectPageTab.value)
|
||||||
|
if (selectPageTab.value === 1) {
|
||||||
|
// Tab 1: 立即加载 P1 数据,其他批次按计划加载
|
||||||
|
handleGetBatch1Data()
|
||||||
|
} else if (selectPageTab.value === 2) {
|
||||||
|
// Tab 2: 延迟加载 P3 数据(用户分析相关)
|
||||||
|
setTimeout(() => {
|
||||||
|
handleGetBatch1Data() // 先加载基础数据
|
||||||
|
handleGetBatch3Data() // 再加载用户分析数据
|
||||||
|
}, 200)
|
||||||
|
} else if (selectPageTab.value === 3 || selectPageTab.value === 4) {
|
||||||
|
// Tab 3&4: 延迟加载 P4 数据(业务管理相关)
|
||||||
|
setTimeout(() => {
|
||||||
|
handleGetBatch1Data() // 先加载基础数据
|
||||||
|
handleGetBatch4Data() // 再加载业务管理数据
|
||||||
|
}, 200)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@ -219,97 +275,133 @@ const timerMethod = () => {
|
|||||||
}, checkInterval);
|
}, checkInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新全部图表的缓存数据的方法
|
// 🚀 分批数据获取方法 (优化性能)
|
||||||
const handleGetUpdateAllData = () => {
|
// P1 批次数据获取 - 基础设施数据 (200ms时触发)
|
||||||
// 清除原本的缓存数据
|
const handleGetBatch1Data = () => {
|
||||||
handleClearCacheData()
|
console.log('🚀 开始获取 P1 批次数据 - 基础设施数据')
|
||||||
|
|
||||||
// 服务区概况
|
// 服务区概况
|
||||||
|
if (OverviewOfServiceAreaRef.value) {
|
||||||
OverviewOfServiceAreaRef.value.handleGetData()
|
OverviewOfServiceAreaRef.value.handleGetData()
|
||||||
|
}
|
||||||
// 交易预警
|
// 交易预警
|
||||||
|
if (TradingAlertRef.value) {
|
||||||
TradingAlertRef.value.handleGetData()
|
TradingAlertRef.value.handleGetData()
|
||||||
// 核心经营数据
|
}
|
||||||
|
// 核心经营数据 (立即加载,地图优先)
|
||||||
|
if (CoreBusinessDataRef.value) {
|
||||||
CoreBusinessDataRef.value.handleGetMapRealData()
|
CoreBusinessDataRef.value.handleGetMapRealData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// P2 批次数据获取 - 流量趋势数据 (600ms时触发)
|
||||||
|
const handleGetBatch2Data = () => {
|
||||||
|
console.log('📈 开始获取 P2 批次数据 - 流量趋势数据')
|
||||||
|
|
||||||
// 断面流量趋势
|
// 断面流量趋势
|
||||||
|
if (TrendOfTrafficFlowRef.value) {
|
||||||
TrendOfTrafficFlowRef.value.handleUpdatePie()
|
TrendOfTrafficFlowRef.value.handleUpdatePie()
|
||||||
|
}
|
||||||
// 入区车流趋势
|
// 入区车流趋势
|
||||||
|
if (VehiclesEnteringRef.value) {
|
||||||
VehiclesEnteringRef.value.handleUpdatePie()
|
VehiclesEnteringRef.value.handleUpdatePie()
|
||||||
// 经营效益
|
}
|
||||||
|
// 经营效益趋势
|
||||||
|
if (VehicleModelStayRef.value) {
|
||||||
VehicleModelStayRef.value.handleUpdatePie()
|
VehicleModelStayRef.value.handleUpdatePie()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// P3 批次数据获取 - 用户分析数据 (1200ms时触发)
|
||||||
|
const handleGetBatch3Data = () => {
|
||||||
|
console.log('👥 开始获取 P3 批次数据 - 用户分析数据')
|
||||||
|
|
||||||
if (CustomerAgeGroupRef.value) {
|
if (CustomerAgeGroupRef.value) {
|
||||||
// 年龄
|
|
||||||
CustomerAgeGroupRef.value.handleUpdatePie()
|
CustomerAgeGroupRef.value.handleUpdatePie()
|
||||||
}
|
}
|
||||||
if (GenderCustomerGroupRef.value) {
|
if (GenderCustomerGroupRef.value) {
|
||||||
// 性别
|
|
||||||
GenderCustomerGroupRef.value.handleUpdatePie()
|
GenderCustomerGroupRef.value.handleUpdatePie()
|
||||||
}
|
}
|
||||||
if (PreferenceTypeRef.value) {
|
if (PreferenceTypeRef.value) {
|
||||||
// 偏好类型
|
|
||||||
PreferenceTypeRef.value.handleUpdatePie()
|
PreferenceTypeRef.value.handleUpdatePie()
|
||||||
}
|
}
|
||||||
if (CustomerGroupRef.value) {
|
if (CustomerGroupRef.value) {
|
||||||
// 客群特征分析
|
|
||||||
CustomerGroupRef.value.handleUpdatePie()
|
CustomerGroupRef.value.handleUpdatePie()
|
||||||
}
|
}
|
||||||
if (CustomerConsumptionPreferencesRef.value) {
|
if (CustomerConsumptionPreferencesRef.value) {
|
||||||
// 客群消费偏好
|
|
||||||
CustomerConsumptionPreferencesRef.value.handleUpdatePie()
|
CustomerConsumptionPreferencesRef.value.handleUpdatePie()
|
||||||
}
|
}
|
||||||
if (ConsumptionConversionRef.value) {
|
if (ConsumptionConversionRef.value) {
|
||||||
// 消费转化率对比图
|
|
||||||
ConsumptionConversionRef.value.handleUpdatePie()
|
ConsumptionConversionRef.value.handleUpdatePie()
|
||||||
}
|
}
|
||||||
if (ConsumptionConversionRef.value) {
|
if (ConsumptionLevelRef.value) {
|
||||||
// 消费水平
|
ConsumptionLevelRef.value.handleUpdatePie()
|
||||||
ConsumptionConversionRef.value.handleUpdatePie()
|
|
||||||
}
|
}
|
||||||
if (ConsumptionPeriodRef.value) {
|
if (ConsumptionPeriodRef.value) {
|
||||||
// 消费时段分析
|
|
||||||
ConsumptionPeriodRef.value.handleUpdatePie()
|
ConsumptionPeriodRef.value.handleUpdatePie()
|
||||||
}
|
}
|
||||||
if (BrandConsumptionLevelRef.value) {
|
if (BrandConsumptionLevelRef.value) {
|
||||||
// 品牌消费水平
|
|
||||||
BrandConsumptionLevelRef.value.handleUpdatePie()
|
BrandConsumptionLevelRef.value.handleUpdatePie()
|
||||||
}
|
}
|
||||||
if (BusinessCaseRef.value) {
|
if (BusinessCaseRef.value) {
|
||||||
// 营收特征
|
|
||||||
BusinessCaseRef.value.handleUpdatePie()
|
BusinessCaseRef.value.handleUpdatePie()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// P4 批次数据获取 - 业务管理数据 (1800ms时触发)
|
||||||
|
const handleGetBatch4Data = () => {
|
||||||
|
console.log('🏢 开始获取 P4 批次数据 - 业务管理数据')
|
||||||
|
|
||||||
if (RegionalRevenueRef.value) {
|
if (RegionalRevenueRef.value) {
|
||||||
// 区域营收占比
|
|
||||||
RegionalRevenueRef.value.handleUpdatePie()
|
RegionalRevenueRef.value.handleUpdatePie()
|
||||||
}
|
}
|
||||||
if (BusinessStructureRef.value) {
|
if (BusinessStructureRef.value) {
|
||||||
// 业态结构占比
|
|
||||||
BusinessStructureRef.value.handleUpdatePie()
|
BusinessStructureRef.value.handleUpdatePie()
|
||||||
}
|
}
|
||||||
if (FestivalRevenueSumInfoRef.value) {
|
if (FestivalRevenueSumInfoRef.value) {
|
||||||
// 节假日营收
|
|
||||||
FestivalRevenueSumInfoRef.value.handleUpdatePie()
|
FestivalRevenueSumInfoRef.value.handleUpdatePie()
|
||||||
}
|
}
|
||||||
if (HotProductListRef.value) {
|
|
||||||
// 热门商品榜单
|
|
||||||
HotProductListRef.value.handleUpdatePie()
|
|
||||||
}
|
|
||||||
if (BrandDetailRef.value) {
|
if (BrandDetailRef.value) {
|
||||||
// 商户类别比例图 和 下面的列表
|
|
||||||
BrandDetailRef.value.handleUpdatePie()
|
BrandDetailRef.value.handleUpdatePie()
|
||||||
}
|
}
|
||||||
if (SupplierListBoxRef.value) {
|
if (SupplierListBoxRef.value) {
|
||||||
// 供应商
|
|
||||||
SupplierListBoxRef.value.handleGetData()
|
SupplierListBoxRef.value.handleGetData()
|
||||||
}
|
}
|
||||||
if (MallOrderStatisticsRef.value) {
|
if (MallOrderStatisticsRef.value) {
|
||||||
// 商城订单统计
|
|
||||||
MallOrderStatisticsRef.value.handleGetData()
|
MallOrderStatisticsRef.value.handleGetData()
|
||||||
}
|
}
|
||||||
if (ThisMonthBenefitsRef.value) {
|
if (ThisMonthBenefitsRef.value) {
|
||||||
// 本月福利金额
|
|
||||||
ThisMonthBenefitsRef.value.handleGetData()
|
ThisMonthBenefitsRef.value.handleGetData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// P5 批次数据获取 - 其他组件数据 (2400ms时触发)
|
||||||
|
const handleGetBatch5Data = () => {
|
||||||
|
console.log('📋 开始获取 P5 批次数据 - 其他组件数据')
|
||||||
|
|
||||||
|
if (HotProductListRef.value) {
|
||||||
|
HotProductListRef.value.handleUpdatePie()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新全部图表的缓存数据的方法 (优化版本 - 使用分批策略)
|
||||||
|
const handleGetUpdateAllData = () => {
|
||||||
|
console.log('🔄 开始更新所有数据 - 使用分批策略')
|
||||||
|
|
||||||
|
// 清除原本的缓存数据
|
||||||
|
handleClearCacheData()
|
||||||
|
|
||||||
|
// 🚀 使用分批数据获取策略,避免一次性请求过多数据造成阻塞
|
||||||
|
// 立即执行第一批数据 (核心数据)
|
||||||
|
handleGetBatch1Data()
|
||||||
|
|
||||||
|
// 稍后执行其他批次数据
|
||||||
|
setTimeout(handleGetBatch2Data, 100) // 100ms后获取流量数据
|
||||||
|
setTimeout(handleGetBatch3Data, 300) // 300ms后获取用户分析数据
|
||||||
|
setTimeout(handleGetBatch4Data, 600) // 600ms后获取业务管理数据
|
||||||
|
setTimeout(handleGetBatch5Data, 1000) // 1000ms后获取其他数据
|
||||||
|
}
|
||||||
|
|
||||||
// 清空原先的缓存数据
|
// 清空原先的缓存数据
|
||||||
const handleClearCacheData = () => {
|
const handleClearCacheData = () => {
|
||||||
// 清除服务区概况的设备信息的缓存
|
// 清除服务区概况的设备信息的缓存
|
||||||
@ -402,10 +494,35 @@ const handleGetCurrentService = (obj: any) => {
|
|||||||
// currentService.value = obj
|
// currentService.value = obj
|
||||||
}
|
}
|
||||||
|
|
||||||
// 改变选择的页面tab
|
// 改变选择的页面tab (优化版本 - 智能数据加载)
|
||||||
const handleChangePageTab = (value: number) => {
|
const handleChangePageTab = (value: number) => {
|
||||||
|
console.log('🔄 Tab切换 - 从', selectPageTab.value, '到', value)
|
||||||
selectPageTab.value = value
|
selectPageTab.value = value
|
||||||
currentService.value = null
|
currentService.value = null
|
||||||
|
|
||||||
|
// 🎯 智能数据加载:根据切换到的Tab加载对应数据
|
||||||
|
if (value === 1) {
|
||||||
|
// Tab 1: 营收监控 - 加载流量和趋势数据
|
||||||
|
setTimeout(() => {
|
||||||
|
handleGetBatch2Data() // 流量趋势数据
|
||||||
|
}, 100)
|
||||||
|
} else if (value === 2) {
|
||||||
|
// Tab 2: 客群画像 - 加载用户分析数据
|
||||||
|
setTimeout(() => {
|
||||||
|
handleGetBatch3Data() // 用户分析数据
|
||||||
|
}, 100)
|
||||||
|
} else if (value === 3) {
|
||||||
|
// Tab 3: 商户生态 - 加载业务管理数据
|
||||||
|
setTimeout(() => {
|
||||||
|
handleGetBatch4Data() // 业务管理数据
|
||||||
|
}, 100)
|
||||||
|
} else if (value === 4) {
|
||||||
|
// Tab 4: 会员商城 - 加载商城和品牌数据
|
||||||
|
setTimeout(() => {
|
||||||
|
handleGetBatch4Data() // 业务管理数据(包含商城)
|
||||||
|
handleGetBatch5Data() // 其他组件数据
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 拿到消息滚动框里面的全部id
|
// 拿到消息滚动框里面的全部id
|
||||||
@ -453,6 +570,12 @@ const handleGetMapLegend = (list: any) => {
|
|||||||
mapLegend.value = list
|
mapLegend.value = list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 🎯 地图加载完成回调 (关键优化)
|
||||||
|
const handleMapLoaded = () => {
|
||||||
|
console.log('🗺️ 地图加载完成 - 布局已稳定')
|
||||||
|
mapLoaded.value = true
|
||||||
|
}
|
||||||
|
|
||||||
// 给地图的修改来自哪里
|
// 给地图的修改来自哪里
|
||||||
const handleChangeComeForm = (str: string) => {
|
const handleChangeComeForm = (str: string) => {
|
||||||
mapClickComeForm.value = str
|
mapClickComeForm.value = str
|
||||||
@ -519,13 +642,13 @@ const handleGetHighWayData = async () => {
|
|||||||
<div class="content169" v-show="selectPageTab === 1">
|
<div class="content169" v-show="selectPageTab === 1">
|
||||||
<div class="content169Left">
|
<div class="content169Left">
|
||||||
<!-- 消息轮播框 -->
|
<!-- 消息轮播框 -->
|
||||||
<NoticeListBox v-if="selectPageTab === 1" :currentService="currentService"
|
<NoticeListBox v-show="selectPageTab === 1 && showBatch1" :currentService="currentService"
|
||||||
:selectPageTab="selectPageTab" @handelGetNoticeListAllId="handelGetNoticeListAllId" />
|
:selectPageTab="selectPageTab" @handelGetNoticeListAllId="handelGetNoticeListAllId" />
|
||||||
|
|
||||||
<!-- <modalTitle :title="'流量趋势'" style="margin-top: 20px;" /> -->
|
<!-- <modalTitle :title="'流量趋势'" style="margin-top: 20px;" /> -->
|
||||||
|
|
||||||
<div v-show="selectPageTab === 1">
|
<div v-show="selectPageTab === 1">
|
||||||
<div class="content169LeftContent">
|
<div class="content169LeftContent" v-show="showBatch1 && mapLoaded">
|
||||||
<!-- 服务区概况 -->
|
<!-- 服务区概况 -->
|
||||||
<OverviewOfServiceArea ref="OverviewOfServiceAreaRef" />
|
<OverviewOfServiceArea ref="OverviewOfServiceAreaRef" />
|
||||||
|
|
||||||
@ -572,7 +695,7 @@ const handleGetHighWayData = async () => {
|
|||||||
<PageMap @handleGetCurrentService="handleGetCurrentService" :noticeMessageObj="noticeMessageObj"
|
<PageMap @handleGetCurrentService="handleGetCurrentService" :noticeMessageObj="noticeMessageObj"
|
||||||
:selectPointServicePart="noticeAllServicePartId" :mapClickComeForm="mapClickComeForm"
|
:selectPointServicePart="noticeAllServicePartId" :mapClickComeForm="mapClickComeForm"
|
||||||
@handleMapToChangeNotice="handleMapToChangeNotice" @handleGetMapLegend="handleGetMapLegend"
|
@handleMapToChangeNotice="handleMapToChangeNotice" @handleGetMapLegend="handleGetMapLegend"
|
||||||
@handleChangeComeForm="handleChangeComeForm" />
|
@handleChangeComeForm="handleChangeComeForm" @mapLoaded="handleMapLoaded" />
|
||||||
|
|
||||||
<div class="AreaLegend">
|
<div class="AreaLegend">
|
||||||
<div class="AreaLegendContent">
|
<div class="AreaLegendContent">
|
||||||
@ -624,12 +747,12 @@ const handleGetHighWayData = async () => {
|
|||||||
|
|
||||||
<div class="content169Right">
|
<div class="content169Right">
|
||||||
<!-- 时间天气等内容 -->
|
<!-- 时间天气等内容 -->
|
||||||
<BasicMessageBox :currentService="currentService" />
|
<BasicMessageBox v-show="showBatch1" :currentService="currentService" />
|
||||||
|
|
||||||
<div v-if="selectPageTab === 1">
|
<div v-if="selectPageTab === 1">
|
||||||
<NewBigTitleBox title="流量趋势" style="margin-top: 24px;" />
|
<NewBigTitleBox title="流量趋势" style="margin-top: 24px;" />
|
||||||
|
|
||||||
<div class="content169LeftContent" style="margin-top: 21px;">
|
<div class="content169LeftContent" style="margin-top: 21px;" v-show="showBatch2 && mapLoaded">
|
||||||
<div class="leftContentBoxItem">
|
<div class="leftContentBoxItem">
|
||||||
<!-- 断面流量趋势 -->
|
<!-- 断面流量趋势 -->
|
||||||
<TrendOfTrafficFlow ref="TrendOfTrafficFlowRef" :currentService="currentService" />
|
<TrendOfTrafficFlow ref="TrendOfTrafficFlowRef" :currentService="currentService" />
|
||||||
@ -681,7 +804,8 @@ const handleGetHighWayData = async () => {
|
|||||||
<div class="content1692st" v-if="selectPageTab === 2">
|
<div class="content1692st" v-if="selectPageTab === 2">
|
||||||
<div class="content1692stLeft">
|
<div class="content1692stLeft">
|
||||||
<!-- 消息轮播框 -->
|
<!-- 消息轮播框 -->
|
||||||
<NoticeListBox style="margin-top: 20px;width: calc(100% / 3);" :selectPageTab="selectPageTab" />
|
<NoticeListBox v-show="showBatch1" style="margin-top: 20px;width: calc(100% / 3);"
|
||||||
|
:selectPageTab="selectPageTab" />
|
||||||
<!-- 核心经营数据 -->
|
<!-- 核心经营数据 -->
|
||||||
<!-- <modalTitle :title="'核心经营数据'" style="margin-top: 20px;" /> -->
|
<!-- <modalTitle :title="'核心经营数据'" style="margin-top: 20px;" /> -->
|
||||||
<!-- <CoreBusinessData style="position: relative;z-index: 9;" :noTitle="true" /> -->
|
<!-- <CoreBusinessData style="position: relative;z-index: 9;" :noTitle="true" /> -->
|
||||||
@ -689,7 +813,7 @@ const handleGetHighWayData = async () => {
|
|||||||
<!-- 客群画像分析 -->
|
<!-- 客群画像分析 -->
|
||||||
<NewBigTitleBox :title="'客群画像分析'" :type="3" style="margin-top: 20px" />
|
<NewBigTitleBox :title="'客群画像分析'" :type="3" style="margin-top: 20px" />
|
||||||
|
|
||||||
<div class="leftBottomContent">
|
<div class="leftBottomContent" v-show="showBatch3">
|
||||||
<!-- 年龄 -->
|
<!-- 年龄 -->
|
||||||
<CustomerAgeGroup ref="CustomerAgeGroupRef"
|
<CustomerAgeGroup ref="CustomerAgeGroupRef"
|
||||||
style="margin-top: 20px;width: calc((100% - 57px) / 3);" />
|
style="margin-top: 20px;width: calc((100% - 57px) / 3);" />
|
||||||
@ -706,7 +830,7 @@ const handleGetHighWayData = async () => {
|
|||||||
style="margin-left: 34px;margin-top: 20px;width: calc((100% - 57px) / 3);" />
|
style="margin-left: 34px;margin-top: 20px;width: calc((100% - 57px) / 3);" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="left3stBottom" style="margin-top: 0;display: flex;flex-wrap: wrap;">
|
<div class="left3stBottom" style="margin-top: 0;display: flex;flex-wrap: wrap;" v-show="showBatch3">
|
||||||
|
|
||||||
<div class="left3stBottomItem" style="width: calc((100% - 57px) / 3);">
|
<div class="left3stBottomItem" style="width: calc((100% - 57px) / 3);">
|
||||||
<!-- 客群特征分析 -->
|
<!-- 客群特征分析 -->
|
||||||
@ -736,7 +860,7 @@ const handleGetHighWayData = async () => {
|
|||||||
</template>
|
</template>
|
||||||
</NewBigTitleBox>
|
</NewBigTitleBox>
|
||||||
|
|
||||||
<div class="left3stBottom" style="margin-top: 0;display: flex;align-items: center;">
|
<div class="left3stBottom" style="margin-top: 0;display: flex;align-items: center;" v-show="showBatch3">
|
||||||
<div class="left3stBottomItemLeft">
|
<div class="left3stBottomItemLeft">
|
||||||
<div class="left3stBottomItem">
|
<div class="left3stBottomItem">
|
||||||
<!-- 消费转化率对比图 -->
|
<!-- 消费转化率对比图 -->
|
||||||
@ -788,10 +912,10 @@ const handleGetHighWayData = async () => {
|
|||||||
</div>
|
</div>
|
||||||
<div class="content1692stRight">
|
<div class="content1692stRight">
|
||||||
<!-- 时间天气等内容 -->
|
<!-- 时间天气等内容 -->
|
||||||
<BasicMessageBox :currentService="currentService" style="margin-top: 20px;" />
|
<BasicMessageBox v-show="showBatch1" :currentService="currentService" style="margin-top: 20px;" />
|
||||||
|
|
||||||
<NewBigTitleBox :title="'经营业态'" style="margin-top: 20px;" />
|
<NewBigTitleBox :title="'经营业态'" style="margin-top: 20px;" v-show="showBatch4" />
|
||||||
<div class="rightContentBox">
|
<div class="rightContentBox" v-show="showBatch4">
|
||||||
<!-- 区域营收占比 -->
|
<!-- 区域营收占比 -->
|
||||||
<RegionalRevenue ref="RegionalRevenueRef" :currentService="currentService"
|
<RegionalRevenue ref="RegionalRevenueRef" :currentService="currentService"
|
||||||
style="margin-top: 10px;" />
|
style="margin-top: 10px;" />
|
||||||
@ -804,7 +928,7 @@ const handleGetHighWayData = async () => {
|
|||||||
<BusinessStructure ref="BusinessStructureRef" :currentService="currentService" />
|
<BusinessStructure ref="BusinessStructureRef" :currentService="currentService" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<NewBigTitleBox :title="'节假日营收'">
|
<NewBigTitleBox :title="'节假日营收'" v-show="showBatch4">
|
||||||
<!-- <template #extra>
|
<!-- <template #extra>
|
||||||
<div class="FestivalBox">
|
<div class="FestivalBox">
|
||||||
<el-select class="festivalSelect" v-model="FestivalValue" placeholder="Select"
|
<el-select class="festivalSelect" v-model="FestivalValue" placeholder="Select"
|
||||||
@ -817,8 +941,8 @@ const handleGetHighWayData = async () => {
|
|||||||
</NewBigTitleBox>
|
</NewBigTitleBox>
|
||||||
<!-- 节假日营收 -->
|
<!-- 节假日营收 -->
|
||||||
<!-- <FestivalRevenue :currentService="currentService" :FestivalValue="FestivalValue" /> -->
|
<!-- <FestivalRevenue :currentService="currentService" :FestivalValue="FestivalValue" /> -->
|
||||||
<FestivalRevenueSumInfo ref="FestivalRevenueSumInfoRef" :currentService="currentService"
|
<FestivalRevenueSumInfo v-show="showBatch4" ref="FestivalRevenueSumInfoRef"
|
||||||
:FestivalValue="FestivalValue" />
|
:currentService="currentService" :FestivalValue="FestivalValue" />
|
||||||
|
|
||||||
<!-- 电商模块 -->
|
<!-- 电商模块 -->
|
||||||
<!-- <modalTitle :title="'电商模块'" style="margin-top: 20px;" /> -->
|
<!-- <modalTitle :title="'电商模块'" style="margin-top: 20px;" /> -->
|
||||||
@ -844,7 +968,7 @@ const handleGetHighWayData = async () => {
|
|||||||
<div class="content1693st" v-if="selectPageTab === 3">
|
<div class="content1693st" v-if="selectPageTab === 3">
|
||||||
<div class="content1693stItem">
|
<div class="content1693stItem">
|
||||||
<!-- 消息轮播框 -->
|
<!-- 消息轮播框 -->
|
||||||
<NoticeListBox :currentService="currentService" :selectPageTab="selectPageTab" />
|
<NoticeListBox v-show="showBatch1" :currentService="currentService" :selectPageTab="selectPageTab" />
|
||||||
|
|
||||||
<NewBigTitleBox title="应收账款" style="margin-top: 20px;" />
|
<NewBigTitleBox title="应收账款" style="margin-top: 20px;" />
|
||||||
<div style="width: 100%;box-sizing: border-box;padding: 20px 11px;">
|
<div style="width: 100%;box-sizing: border-box;padding: 20px 11px;">
|
||||||
@ -887,20 +1011,20 @@ const handleGetHighWayData = async () => {
|
|||||||
<modalTitle :title="'员工福利与商城数据'" />
|
<modalTitle :title="'员工福利与商城数据'" />
|
||||||
<div class="content1693stItem2stContent">
|
<div class="content1693stItem2stContent">
|
||||||
<!-- 本月福利金发送额度 -->
|
<!-- 本月福利金发送额度 -->
|
||||||
<ThisMonthBenefits />
|
<ThisMonthBenefits v-show="showBatch4" />
|
||||||
|
|
||||||
<!-- 核心品类占比 -->
|
<!-- 核心品类占比 -->
|
||||||
<CoreCategory style="margin-top: 20px;" />
|
<CoreCategory v-show="showBatch5" style="margin-top: 20px;" />
|
||||||
|
|
||||||
<!-- 热门商品榜单 -->
|
<!-- 热门商品榜单 -->
|
||||||
<HotProductList style="margin-top: 30px;" :pageType="'left'" />
|
<HotProductList v-show="showBatch5" style="margin-top: 30px;" :pageType="'left'" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content1693stItem">
|
<div class="content1693stItem">
|
||||||
<!-- 时间天气等内容 -->
|
<!-- 时间天气等内容 -->
|
||||||
<BasicMessageBox :currentService="currentService" />
|
<BasicMessageBox v-show="showBatch1" :currentService="currentService" />
|
||||||
|
|
||||||
<NewBigTitleBox :title="'应收账款'" style="margin-top: 20px;" />
|
<NewBigTitleBox :title="'应收账款'" style="margin-top: 20px;" />
|
||||||
<div style="width: 100%;box-sizing: border-box;padding: 16px 11px 0;">
|
<div style="width: 100%;box-sizing: border-box;padding: 16px 11px 0;">
|
||||||
@ -924,13 +1048,13 @@ const handleGetHighWayData = async () => {
|
|||||||
<div class="content1694st" v-if="selectPageTab === 4">
|
<div class="content1694st" v-if="selectPageTab === 4">
|
||||||
<div class="content1694stItem">
|
<div class="content1694stItem">
|
||||||
<!-- 消息轮播框 -->
|
<!-- 消息轮播框 -->
|
||||||
<NoticeListBox :selectPageTab="selectPageTab" />
|
<NoticeListBox v-show="showBatch1" :selectPageTab="selectPageTab" />
|
||||||
|
|
||||||
<NewBigTitleBox :title="'会员商城'" style="margin-top: 29px;" />
|
<NewBigTitleBox :title="'会员商城'" style="margin-top: 29px;" />
|
||||||
|
|
||||||
<div style="width: 100%;box-sizing: border-box;padding: 20px 11px 0;">
|
<div style="width: 100%;box-sizing: border-box;padding: 20px 11px 0;">
|
||||||
<!-- 会员商城 -->
|
<!-- 会员商城 -->
|
||||||
<MemberMall />
|
<MemberMall v-show="showBatch4" />
|
||||||
|
|
||||||
<!-- 日常巡检(蓝湖的设备完好率) -->
|
<!-- 日常巡检(蓝湖的设备完好率) -->
|
||||||
<!-- <DailyInspection /> -->
|
<!-- <DailyInspection /> -->
|
||||||
@ -939,7 +1063,8 @@ const handleGetHighWayData = async () => {
|
|||||||
<!-- <AssessmentScoringRanking style="margin-top: 19px;" /> -->
|
<!-- <AssessmentScoringRanking style="margin-top: 19px;" /> -->
|
||||||
|
|
||||||
<!-- 热门商品榜单 -->
|
<!-- 热门商品榜单 -->
|
||||||
<HotProductList ref="HotProductListRef" style="margin-top: 20px;" :pageType="'left'" />
|
<HotProductList v-show="showBatch5" ref="HotProductListRef" style="margin-top: 20px;"
|
||||||
|
:pageType="'left'" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 客群特征分析 -->
|
<!-- 客群特征分析 -->
|
||||||
@ -957,12 +1082,12 @@ const handleGetHighWayData = async () => {
|
|||||||
<NewBigTitleBox :title="'品牌'" style="margin-top: 54px;" />
|
<NewBigTitleBox :title="'品牌'" style="margin-top: 54px;" />
|
||||||
|
|
||||||
<!-- 商户类别比例图 和 下面的列表 -->
|
<!-- 商户类别比例图 和 下面的列表 -->
|
||||||
<BrandDetail ref="BrandDetailRef" />
|
<BrandDetail v-show="showBatch4" ref="BrandDetailRef" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content1694stItem">
|
<div class="content1694stItem">
|
||||||
<NewBigTitleBox :title="'供应商'" style="margin-top: 54px;" />
|
<NewBigTitleBox :title="'供应商'" style="margin-top: 54px;" />
|
||||||
<SupplierListBox ref="SupplierListBoxRef" />
|
<SupplierListBox v-show="showBatch4" ref="SupplierListBoxRef" />
|
||||||
<!-- 在线服务区和在线收银机 -->
|
<!-- 在线服务区和在线收银机 -->
|
||||||
<!-- <TodayTrend /> -->
|
<!-- <TodayTrend /> -->
|
||||||
|
|
||||||
@ -974,23 +1099,23 @@ const handleGetHighWayData = async () => {
|
|||||||
</div>
|
</div>
|
||||||
<div class="content1694stItem">
|
<div class="content1694stItem">
|
||||||
<!-- 时间天气等内容 -->
|
<!-- 时间天气等内容 -->
|
||||||
<BasicMessageBox :currentService="currentService" />
|
<BasicMessageBox v-show="showBatch1" :currentService="currentService" />
|
||||||
|
|
||||||
<NewBigTitleBox :title="'电商模块'" style="margin-top: 28px;" />
|
<NewBigTitleBox :title="'电商模块'" style="margin-top: 28px;" />
|
||||||
|
|
||||||
<!-- 商城订单统计 -->
|
<!-- 商城订单统计 -->
|
||||||
<MallOrderStatistics ref="MallOrderStatisticsRef" style="margin-top: 20px;" />
|
<MallOrderStatistics v-show="showBatch4" ref="MallOrderStatisticsRef" style="margin-top: 20px;" />
|
||||||
|
|
||||||
<NewBigTitleBox :title="'商户生态结构图谱'" style="margin-top: 28px;" />
|
<NewBigTitleBox :title="'商户生态结构图谱'" style="margin-top: 28px;" v-show="showBatch4" />
|
||||||
|
|
||||||
<!-- 本月福利金发送额度 -->
|
<!-- 本月福利金发送额度 -->
|
||||||
<ThisMonthBenefits ref="ThisMonthBenefitsRef" style="margin-top: 10px;" />
|
<ThisMonthBenefits v-show="showBatch4" ref="ThisMonthBenefitsRef" style="margin-top: 10px;" />
|
||||||
|
|
||||||
<!-- 核心品类占比 -->
|
<!-- 核心品类占比 -->
|
||||||
<!-- <CoreCategory style="margin-top: 10px;" /> -->
|
<!-- <CoreCategory style="margin-top: 10px;" /> -->
|
||||||
|
|
||||||
<NewBigTitleBox :title="'会员消费数据分析'" />
|
<NewBigTitleBox :title="'会员消费数据分析'" v-show="showBatch5" />
|
||||||
<AnalysisOfMember />
|
<AnalysisOfMember v-show="showBatch5" />
|
||||||
|
|
||||||
<!-- 商户评分排行榜 -->
|
<!-- 商户评分排行榜 -->
|
||||||
<!-- <MerchantRatingRanking style="margin-top: 16px;" /> -->
|
<!-- <MerchantRatingRanking style="margin-top: 16px;" /> -->
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user