You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
745 lines
23 KiB
745 lines
23 KiB
<template>
|
|
<el-col :span="4">
|
|
<el-card class="center-card margin-bottom">数据总览</el-card>
|
|
</el-col>
|
|
<el-row :gutter="10">
|
|
<!-- 第一个卡片 -->
|
|
<el-col :span="6">
|
|
<el-card class="card-item">
|
|
<template #header>
|
|
<div class="card-header">
|
|
<div class="card-title">当前金币余量</div>
|
|
<div>{{ currentGold / 100 }} 较前一日 {{
|
|
dailyChange / 100 }}
|
|
<template v-if="dailyChange > 0">
|
|
<el-icon style="color:red">
|
|
<ArrowUpBold />
|
|
</el-icon>
|
|
</template>
|
|
<template v-else-if="dailyChange < 0">
|
|
<el-icon style="color:forestgreen">
|
|
<ArrowDownBold />
|
|
</el-icon>
|
|
</template>
|
|
<template v-else>
|
|
<el-icon style="color:grey">
|
|
<SemiSelect />
|
|
</el-icon>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<div>
|
|
<div class="margin-bottom">永久金币:{{ currentPermanent / 100 }}</div>
|
|
<div class="margin-bottom">免费金币:{{ currentFree / 100 }}</div>
|
|
<div class="margin-bottom">[六月到期|{{ currentFreeJune / 100 }}] [12月到期|{{
|
|
currentFreeDecember /
|
|
100 }}]</div>
|
|
<div>任务金币:{{ currentTask / 100 }}</div>
|
|
</div>
|
|
</el-card>
|
|
</el-col>
|
|
|
|
<!-- 第二个卡片 -->
|
|
<el-col :span="6">
|
|
<el-card class="card-item">
|
|
<div class="card-title">全年累计充值金币数</div>
|
|
<div class="card-title">{{ yearlyRecharge / 100 }}</div>
|
|
<div> </div>
|
|
<div class="center-card">折合新币累计金额:{{ yearlyMoney / 100 }}</div>
|
|
<template #footer>
|
|
<el-col class="margin-bottom center-card">昨日新增:{{ recharge / 100 }}</el-col>
|
|
<el-col class="margin-bottom center-card">其中充值:{{ money / 100 }}</el-col>
|
|
</template>
|
|
</el-card>
|
|
</el-col>
|
|
|
|
<!-- 第三个卡片 -->
|
|
<el-col :span="6">
|
|
<el-card class="card-item">
|
|
<div class="card-title">全年累计消耗金币数</div>
|
|
<div class="card-title">{{ yearlyReduce / 100 }}</div>
|
|
<div class="center-card">消费:{{ yearlyConsume / 100 }}</div>
|
|
<div class="center-card">退款:{{ yearlyRefund / 100 }}</div>
|
|
<template #footer>
|
|
<div></div>
|
|
<div class="margin-bottom center-card">昨日新增消耗:{{ dailyReduce / 100 }}</div>
|
|
<div class="margin-bottom center-card">昨日新增消费:{{ dailyConsume / 100 }}</div>
|
|
<div class="margin-bottom center-card">昨日新增退款:{{ dailyRefund / 100 }}</div>
|
|
</template>
|
|
</el-card>
|
|
</el-col>
|
|
|
|
<!-- 第四个卡片 -->
|
|
<el-col :span="6">
|
|
<el-card class="card-item">
|
|
<el-col class="card-title">全年累计充值人头数</el-col>
|
|
<el-col class="card-title">{{ yearlyRechargeNum }}</el-col>
|
|
<el-col class="center-card">周同比:{{ sumWow }}%
|
|
<template v-if="sumWow > 0">
|
|
<el-icon style="color:red">
|
|
<ArrowUpBold />
|
|
</el-icon>
|
|
</template>
|
|
<template v-else-if="sumWow < 0">
|
|
<el-icon style="color:forestgreen">
|
|
<ArrowDownBold />
|
|
</el-icon>
|
|
</template>
|
|
<template v-else>
|
|
<el-icon style="color:grey">
|
|
<SemiSelect />
|
|
</el-icon>
|
|
</template>
|
|
</el-col>
|
|
<el-col class="center-card">日环比:{{ sumDaily }}%
|
|
<template v-if="sumDaily > 0">
|
|
<el-icon style="color:red">
|
|
<ArrowUpBold />
|
|
</el-icon>
|
|
</template>
|
|
<template v-else-if="sumDaily < 0">
|
|
<el-icon style="color:forestgreen">
|
|
<ArrowDownBold />
|
|
</el-icon>
|
|
</template>
|
|
<template v-else>
|
|
<el-icon style="color:grey">
|
|
<SemiSelect />
|
|
</el-icon>
|
|
</template>
|
|
</el-col>
|
|
<template #footer>
|
|
<el-col class="margin-bottom center-card">昨日充值人数:{{ rechargeNum }}</el-col>
|
|
<el-col class="margin-bottom center-card">其中首充:{{ firstRecharge }}</el-col>
|
|
</template>
|
|
</el-card>
|
|
</el-col>
|
|
</el-row>
|
|
|
|
<el-row :gutter="10" style="margin-top: 20px">
|
|
<el-col :span="24">
|
|
<el-card style="width: 100%">
|
|
<el-row>
|
|
<el-col :span="21">
|
|
<el-tabs v-model="activeTab" @tab-change="handleTabChange">
|
|
<el-tab-pane label="金币充值" name="recharge"></el-tab-pane>
|
|
<el-tab-pane label="金币消费" name="consume"></el-tab-pane>
|
|
</el-tabs>
|
|
</el-col>
|
|
<el-col :span="24">
|
|
<el-row>
|
|
<div style="margin-top:5px">合计
|
|
永久金币 {{ activeTab === 'recharge' ? sumRechargePermanent / 100 : sumConsumePermanent / 100
|
|
}}
|
|
免费金币 {{ activeTab === 'recharge' ? sumRechargeFree / 100 : sumConsumeFree / 100
|
|
}}
|
|
任务金币 {{ activeTab === 'recharge' ? sumRechargeTask / 100 : sumConsumeTask / 100
|
|
}}
|
|
</div>
|
|
<div>
|
|
<el-button @click="getToday()" label="day" style="margin-left:250px">今日</el-button>
|
|
<el-button @click="getWeek()" label="week">本周</el-button>
|
|
<el-button @click="getMonth()" label="month">本月</el-button>
|
|
<el-button @click="getYear()" label="year">本年</el-button>
|
|
</div>
|
|
<el-date-picker v-model="dateRange" type="datetimerange" range-separator="→" start-placeholder="开始时间"
|
|
end-placeholder="结束时间" style="margin-left:10px" />
|
|
<el-button type="primary" style="margin-left: 5px" @click="getChartData">查询</el-button>
|
|
</el-row>
|
|
</el-col>
|
|
</el-row>
|
|
|
|
<el-row :gutter="20" style="margin-top: 20px">
|
|
<el-col :span="18">
|
|
<div class="bar">
|
|
<div ref="chartRef" style="width: 100%; height: 400px"></div>
|
|
</div>
|
|
</el-col>
|
|
<el-col :span="6">
|
|
<el-card class="rank-card" style="width: 100%; height: 100%">
|
|
<div class="card-large margin-bottom">金币{{ activeTab === 'recharge' ? '充值' : '消费' }}排名</div>
|
|
<el-select v-model="selectedType" style="width: 100%; margin-bottom: 15px">
|
|
<el-option label="全部类型" value="all"></el-option>
|
|
<el-option label="永久金币" value="permanent"></el-option>
|
|
<el-option label="免费金币" value="free"></el-option>
|
|
<el-option label="任务金币" value="task"></el-option>
|
|
</el-select>
|
|
<el-table :data="tableData" height="320px">
|
|
<el-table-column prop="rank" label="排名" width="60" align="center"></el-table-column>
|
|
<el-table-column prop="market" label="地区" align="center"></el-table-column>
|
|
<el-table-column prop="coinAmount" label="金币数量" align="center">
|
|
<template #default="{ row }">
|
|
{{ row.coinAmount.toLocaleString() }}
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
</el-card>
|
|
</el-col>
|
|
</el-row>
|
|
</el-card>
|
|
</el-col>
|
|
</el-row>
|
|
</template>
|
|
|
|
<script setup>
|
|
import * as echarts from 'echarts'
|
|
import { ref, onMounted, nextTick, watch } from 'vue'
|
|
import API from '@/util/http'
|
|
import { ElMessage } from 'element-plus'
|
|
import dayjs from 'dayjs';
|
|
import utc from 'dayjs-plugin-utc'
|
|
dayjs.extend(utc)
|
|
import { ArrowUpBold, ArrowDownBold, SemiSelect } from '@element-plus/icons-vue'
|
|
// 地区数据
|
|
const markets = ref([])
|
|
// 图表相关
|
|
const dateRange = ref([])
|
|
const activeTab = ref('recharge')
|
|
const selectedType = ref('all')
|
|
const tableData = ref([])
|
|
const chartRef = ref(null)
|
|
let chartInstance = null
|
|
// 图表合计数
|
|
const sumRechargePermanent = ref(0)
|
|
const sumRechargeFree = ref(0)
|
|
const sumRechargeTask = ref(0)
|
|
const sumConsumePermanent = ref(0)
|
|
const sumConsumeFree = ref(0)
|
|
const sumConsumeTask = ref(0)
|
|
// 用户信息
|
|
const adminData = ref({})
|
|
// 卡片数据相关
|
|
const currentGold = ref(0)
|
|
const dailyChange = ref(0)
|
|
const currentPermanent = ref(0)
|
|
const currentFree = ref(0)
|
|
const currentFreeJune = ref(0)
|
|
const currentFreeDecember = ref(0)
|
|
const currentTask = ref(0)
|
|
const yearlyRecharge = ref(0)
|
|
const yearlyMoney = ref(0)
|
|
const recharge = ref(0)
|
|
const money = ref(0)
|
|
const yearlyReduce = ref(0)
|
|
const yearlyConsume = ref(0)
|
|
const yearlyRefund = ref(0)
|
|
const dailyReduce = ref(0)
|
|
const dailyConsume = ref(0)
|
|
const dailyRefund = ref(0)
|
|
const yearlyRechargeNum = ref(0)
|
|
const sumWow = ref(0)
|
|
const sumDaily = ref(0)
|
|
const rechargeNum = ref(0)
|
|
const firstRecharge = ref(0)
|
|
const length = ref(0)
|
|
const formatDate = function(date) {
|
|
const year = date.getFullYear();
|
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
const day = String(date.getDate()).padStart(2, '0');
|
|
const hours = String(date.getHours()).padStart(2, '0');
|
|
const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
const seconds = String(date.getSeconds()).padStart(2, '0');
|
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
}
|
|
// 今天
|
|
const getToday = function () {
|
|
const today = new Date()
|
|
const startTime = new Date(today.getFullYear(), today.getMonth(), today.getDate())
|
|
const endTime = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1)
|
|
dateRange.value = [formatDate(startTime), formatDate(endTime)]
|
|
console.log('看看dateRange', dateRange.value)
|
|
}
|
|
// 本周
|
|
const getWeek = function () {
|
|
const today = new Date()
|
|
const startTime = new Date(today.getFullYear(), today.getMonth(), today.getDate() - 6)
|
|
const endTime = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1)
|
|
dateRange.value = [formatDate(startTime), formatDate(endTime)]
|
|
console.log('看看dateRange', dateRange.value)
|
|
}
|
|
// 本月
|
|
const getMonth = function () {
|
|
const today = new Date()
|
|
const startTime = new Date(today.getFullYear(), today.getMonth(), 1)
|
|
const endTime = new Date(today.getFullYear(), today.getMonth() + 1, 1)
|
|
dateRange.value = [formatDate(startTime), formatDate(endTime)]
|
|
console.log('看看dateRange', dateRange.value)
|
|
}
|
|
// 本年
|
|
const getYear = function () {
|
|
const today = new Date()
|
|
const startTime = new Date(today.getFullYear(), 0, 1)
|
|
const endTime = new Date(today.getFullYear() + 1, 0, 1)
|
|
dateRange.value = [formatDate(startTime), formatDate(endTime)]
|
|
console.log('看看dateRange', dateRange.value)
|
|
}
|
|
|
|
// 要加上所有市场的,还有额外计算的(总数 = 永久 + 6月 + 12月 + 免费 + 任务)
|
|
const processData = (data) => {
|
|
const summary = {
|
|
currentGold: 0,
|
|
dailyChange: 0,
|
|
currentPermanent: 0,
|
|
currentFreeJune: 0,
|
|
currentFreeDecember: 0,
|
|
currentTask: 0,
|
|
currentFree: 0,
|
|
recharge: 0,
|
|
money: 0,
|
|
yearlyRecharge: 0,
|
|
yearlyMoney: 0,
|
|
consumePermanent: 0,
|
|
consumeFreeJune: 0,
|
|
consumeFreeDecember: 0,
|
|
consumeTask: 0,
|
|
refundPermanent: 0,
|
|
refundFreeJune: 0,
|
|
refundFreeDecember: 0,
|
|
refundTask: 0,
|
|
dailyReduce: 0,
|
|
yearlyConsume: 0,
|
|
yearlyRefund: 0,
|
|
yearlyReduce: 0,
|
|
rechargeNum: 0,
|
|
firstRecharge: 0,
|
|
sumWow: 0,
|
|
sumDaily: 0,
|
|
yearlyRechargeNum: 0
|
|
}
|
|
|
|
// 遍历市场
|
|
data.marketCards.forEach(market => {
|
|
for (const i in summary) {
|
|
if (market[i] !== undefined && market[i] !== null) { // 其实还应该卡一个number
|
|
summary[i] += market[i]
|
|
}
|
|
}
|
|
})
|
|
|
|
// wow和daily除一下
|
|
length.value = data.markets.length
|
|
console.log(length.value)
|
|
|
|
// 计算昨日新增消费和退款
|
|
const yesterdayConsume = summary.consumePermanent + summary.consumeFreeJune + summary.consumeFreeDecember + summary.consumeTask
|
|
const yesterdayRefund = summary.refundPermanent + summary.refundFreeJune + summary.refundFreeDecember + summary.refundTask
|
|
|
|
// 更新卡片数据
|
|
currentGold.value = summary.currentGold
|
|
dailyChange.value = summary.dailyChange
|
|
currentPermanent.value = summary.currentPermanent
|
|
currentFree.value = summary.currentFree
|
|
currentFreeJune.value = summary.currentFreeJune
|
|
currentFreeDecember.value = summary.currentFreeDecember
|
|
currentTask.value = summary.currentTask
|
|
|
|
yearlyRecharge.value = summary.yearlyRecharge
|
|
yearlyMoney.value = summary.yearlyMoney
|
|
recharge.value = summary.recharge
|
|
money.value = summary.money
|
|
|
|
yearlyReduce.value = summary.yearlyReduce
|
|
yearlyConsume.value = summary.yearlyConsume
|
|
yearlyRefund.value = summary.yearlyRefund
|
|
dailyReduce.value = summary.dailyReduce
|
|
dailyConsume.value = yesterdayConsume
|
|
dailyRefund.value = yesterdayRefund
|
|
|
|
yearlyRechargeNum.value = summary.yearlyRechargeNum
|
|
sumWow.value = summary.sumWow / length.value
|
|
sumDaily.value = summary.sumDaily / length.value
|
|
rechargeNum.value = summary.rechargeNum
|
|
firstRecharge.value = summary.firstRecharge
|
|
}
|
|
|
|
// 获取市场列表
|
|
const getMarkets = async () => {
|
|
try {
|
|
const response = await API({ url: '/general/market', data: {} })
|
|
if (Array.isArray(response.data)) {
|
|
markets.value = response.data
|
|
console.log('市场列表获取成功:', markets.value)
|
|
} else {
|
|
console.error('获取市场列表失败', response)
|
|
ElMessage.error('获取市场列表失败')
|
|
}
|
|
} catch (error) {
|
|
console.error('获取市场列表失败:', error)
|
|
ElMessage.error('获取市场列表失败')
|
|
}
|
|
}
|
|
|
|
// 获取图表数据
|
|
const getChartData = async () => {
|
|
try {
|
|
// 校验市场数据到底有没有
|
|
if (!markets.value || markets.value.length === 0) {
|
|
await getMarkets()
|
|
}
|
|
|
|
|
|
const params = {
|
|
markets: markets.value,
|
|
startDate: dateRange.value[0],
|
|
endDate: dateRange.value[1]
|
|
};
|
|
|
|
|
|
const response = await API({
|
|
url: '/workbench/getGraph',
|
|
data: params
|
|
})
|
|
console.log('看看params', params)
|
|
if (Array.isArray(response.marketGraphs)) {
|
|
// 处理图表数据
|
|
processChartData(response.marketGraphs)
|
|
// 处理排名数据
|
|
processRankingData(response.marketGraphs)
|
|
} else {
|
|
console.error('获取图表数据失败:', response)
|
|
ElMessage.error('获取图表数据失败')
|
|
}
|
|
} catch (error) {
|
|
console.error('获取图表数据失败:', error)
|
|
ElMessage.error('获取图表数据失败')
|
|
}
|
|
}
|
|
// 处理图表数据
|
|
const processChartData = (marketCards) => {
|
|
// 准备图表数据
|
|
const chartData = {
|
|
rechargePermanent: [],
|
|
rechargeFree: [],
|
|
rechargeTask: [],
|
|
consumePermanent: [],
|
|
consumeFree: [],
|
|
consumeTask: []
|
|
}
|
|
// 这是图表的合计数,怎样遍历?????
|
|
const sumRechargePermanent1 = ref(0)
|
|
const sumRechargeFree1 = ref(0)
|
|
const sumRechargeTask1 = ref(0)
|
|
const sumConsumePermanent1 = ref(0)
|
|
const sumConsumeFree1 = ref(0)
|
|
const sumConsumeTask1 = ref(0)
|
|
|
|
// 按市场组织数据
|
|
marketCards.forEach(market => {
|
|
chartData.rechargePermanent.push(market.sumRechargePermanent / 100 || 0)
|
|
chartData.rechargeFree.push(market.sumRechargeFree / 100 || 0)
|
|
chartData.rechargeTask.push(market.sumRechargeTask / 100 || 0)
|
|
chartData.consumePermanent.push(market.sumConsumePermanent / 100 || 0)
|
|
chartData.consumeFree.push(market.sumConsumeFree / 100 || 0)
|
|
chartData.consumeTask.push(market.sumConsumeTask / 100 || 0)
|
|
|
|
// 合计数合计数合计数咋算
|
|
sumRechargePermanent1.value += (market.sumRechargePermanent || 0)
|
|
sumRechargeFree1.value += (market.sumRechargeFree || 0)
|
|
//sumRechargeTask1.value += (market.sumRechargeTask || 0)
|
|
sumConsumePermanent1.value += (market.sumConsumePermanent || 0)
|
|
sumConsumeFree1.value += (market.sumConsumeFree || 0)
|
|
sumConsumeTask1.value += (market.sumConsumeTask || 0)
|
|
})
|
|
sumRechargePermanent.value = sumRechargePermanent1.value
|
|
sumRechargeFree.value = sumRechargeFree1.value
|
|
sumRechargeTask.value = 0
|
|
sumConsumePermanent.value = sumConsumePermanent1.value
|
|
sumConsumeFree.value = sumConsumeFree1.value
|
|
sumConsumeTask.value = sumConsumeTask1.value
|
|
|
|
// 根据当前选中的标签更新图表
|
|
updateChart(chartData)
|
|
}
|
|
|
|
const processRankingData = (marketCards) => {
|
|
// 根据当前选中的标签和类型计算每个市场的总金币数量
|
|
const rankingData = marketCards.map(market => {
|
|
let coinAmount = 0;
|
|
if (activeTab.value === 'recharge') {
|
|
// 充值排名
|
|
switch (selectedType.value) {
|
|
case 'all':
|
|
coinAmount = (market.sumRechargePermanent / 100 || 0) + (market.sumRechargeFree / 100 || 0) + (market.sumRechargeTask / 100 || 0);
|
|
break;
|
|
case 'permanent':
|
|
coinAmount = market.sumRechargePermanent / 100 || 0;
|
|
break;
|
|
case 'free':
|
|
coinAmount = market.sumRechargeFree / 100 || 0;
|
|
break;
|
|
case 'task':
|
|
coinAmount = market.sumRechargeTask / 100 || 0;
|
|
break;
|
|
}
|
|
} else {
|
|
// 消费排名
|
|
switch (selectedType.value) {
|
|
case 'all':
|
|
coinAmount = (market.sumConsumePermanent / 100 || 0) + (market.sumConsumeFree / 100 || 0) + (market.sumConsumeTask / 100 || 0);
|
|
break;
|
|
case 'permanent':
|
|
coinAmount = market.sumConsumePermanent / 100 || 0;
|
|
break;
|
|
case 'free':
|
|
coinAmount = market.sumConsumeFree / 100 || 0;
|
|
break;
|
|
case 'task':
|
|
coinAmount = market.sumConsumeTask / 100 || 0;
|
|
break;
|
|
}
|
|
}
|
|
return {
|
|
market: market.market, // 使用 market 字段作为地区名称
|
|
coinAmount: coinAmount
|
|
};
|
|
});
|
|
|
|
// 按金币数量排序
|
|
rankingData.sort((a, b) => b.coinAmount - a.coinAmount);
|
|
|
|
// 添加排名序号
|
|
tableData.value = rankingData.map((item, index) => ({
|
|
rank: index + 1,
|
|
...item
|
|
}));
|
|
}
|
|
|
|
// 监听 selectedType 的变化,重新处理排名数据
|
|
watch(selectedType, () => {
|
|
getChartData();
|
|
});
|
|
// 更新图表
|
|
const updateChart = (chartData) => {
|
|
if (!chartInstance) {
|
|
chartInstance = echarts.init(chartRef.value)
|
|
}
|
|
|
|
let series = []
|
|
let legend = []
|
|
|
|
if (activeTab.value === 'recharge') {
|
|
series = [
|
|
{
|
|
name: '永久金币',
|
|
type: 'bar',
|
|
stack: 'recharge',
|
|
data: chartData.rechargePermanent,
|
|
itemStyle: { color: '#5470c6' },
|
|
barWidth: 30
|
|
},
|
|
{
|
|
name: '免费金币',
|
|
type: 'bar',
|
|
stack: 'recharge',
|
|
data: chartData.rechargeFree,
|
|
itemStyle: { color: '#91cc75' },
|
|
barWidth: 30
|
|
},
|
|
{
|
|
name: '任务金币',
|
|
type: 'bar',
|
|
stack: 'recharge',
|
|
data: chartData.rechargeTask,
|
|
itemStyle: { color: '#fac858' },
|
|
barWidth: 30
|
|
}
|
|
]
|
|
legend = ['永久金币', '免费金币', '任务金币']
|
|
} else {
|
|
series = [
|
|
{
|
|
name: '永久金币',
|
|
type: 'bar',
|
|
stack: 'consume',
|
|
data: chartData.consumePermanent,
|
|
itemStyle: { color: '#5470c6' },
|
|
barWidth: 30
|
|
},
|
|
{
|
|
name: '免费金币',
|
|
type: 'bar',
|
|
stack: 'consume',
|
|
data: chartData.consumeFree,
|
|
itemStyle: { color: '#91cc75' },
|
|
barWidth: 30
|
|
},
|
|
{
|
|
name: '任务金币',
|
|
type: 'bar',
|
|
stack: 'consume',
|
|
data: chartData.consumeTask,
|
|
itemStyle: { color: '#fac858' },
|
|
barWidth: 30
|
|
}
|
|
]
|
|
legend = ['永久金币', '免费金币', '任务金币']
|
|
}
|
|
|
|
// 设置图表选项
|
|
const option = {
|
|
tooltip: {
|
|
trigger: 'axis',
|
|
axisPointer: {
|
|
type: 'shadow'
|
|
},
|
|
formatter: function (params) {
|
|
let result = params[0].name + '<br/>'
|
|
params.forEach(param => {
|
|
result += `${param.seriesName}: ${param.value.toLocaleString()}<br/>`
|
|
})
|
|
return result
|
|
}
|
|
},
|
|
legend: {
|
|
data: legend,
|
|
bottom: 10
|
|
},
|
|
grid: {
|
|
left: '3%',
|
|
right: '4%',
|
|
bottom: '15%',
|
|
containLabel: true
|
|
},
|
|
xAxis: {
|
|
type: 'category',
|
|
data: markets.value,
|
|
axisLabel: {
|
|
interval: 0,
|
|
rotate: 30
|
|
}
|
|
},
|
|
yAxis: {
|
|
type: 'value',
|
|
axisLabel: {
|
|
formatter: function (value) {
|
|
return value.toLocaleString()
|
|
}
|
|
}
|
|
},
|
|
series: series
|
|
}
|
|
|
|
chartInstance.setOption(option)
|
|
}
|
|
|
|
// 处理标签切换
|
|
const handleTabChange = () => {
|
|
getChartData()
|
|
console.log('标签切换调用图表')
|
|
}
|
|
|
|
const getAdminData = async function () {
|
|
try {
|
|
const result = await API({ url: '/admin/userinfo', data: {} })
|
|
adminData.value = result
|
|
console.log('用户信息', adminData.value)
|
|
} catch (error) {
|
|
console.log('请求失败', error)
|
|
}
|
|
}
|
|
// 获取卡片数据
|
|
const getCardData = async () => {
|
|
try {
|
|
const response = await API({ url: '/workbench/getCard', data: {} })
|
|
if (response && response.data) {
|
|
processData(response.data)
|
|
} else if (Array.isArray(response?.marketCards)) {
|
|
processData(response)
|
|
} else {
|
|
console.error('无效的API响应结构:', response)
|
|
}
|
|
} catch (error) {
|
|
console.error('获取卡片数据失败:', error)
|
|
}
|
|
}
|
|
|
|
|
|
onMounted(async () => {
|
|
|
|
await getAdminData()
|
|
await getCardData()
|
|
await getMarkets()
|
|
getYear()
|
|
await getChartData()
|
|
console.log('挂载后调用')
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.center-card {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
.margin-bottom {
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.card-item {
|
|
height: 260px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
}
|
|
|
|
.card-title {
|
|
font-weight: bold;
|
|
margin-bottom: 10px;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
.rank-card {
|
|
height: 500px;
|
|
}
|
|
|
|
.card-large {
|
|
font-weight: bold;
|
|
font-size: 16px;
|
|
text-align: center;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
.bar {
|
|
background: white;
|
|
border-radius: 8px;
|
|
padding: 15px;
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
/* 添加加载动画 */
|
|
.loading-overlay {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background: rgba(255, 255, 255, 0.8);
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
z-index: 10;
|
|
}
|
|
|
|
.loading-spinner {
|
|
width: 40px;
|
|
height: 40px;
|
|
border: 4px solid #f3f3f3;
|
|
border-top: 4px solid #3498db;
|
|
border-radius: 50%;
|
|
animation: spin 1s linear infinite;
|
|
}
|
|
|
|
@keyframes spin {
|
|
0% {
|
|
transform: rotate(0deg);
|
|
}
|
|
|
|
100% {
|
|
transform: rotate(360deg);
|
|
}
|
|
}
|
|
</style>
|