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.
 
 
 

667 lines
18 KiB

<template>
<div class="gold-management">
<div class="gold-title">
<div class="text1">
金币管理
<span class="text1-update-time">最后更新时间{{
workDataUpdateTime && workDataUpdateTime !== '1970-01-01 08:00:00' ? workDataUpdateTime : '该地区暂无数据'
}} </span>
</div>
</div>
<!-- 第一行包含两个横向格子 -->
<el-row>
<el-col :span="12">
<!-- 第一个卡片 -->
<div class="card-item-row1">
<div class="card-title">当前金币余量
<span style="font-weight: bold">{{
currentGold / 100
}}</span>&nbsp;&nbsp;&nbsp;&nbsp;较前一日
{{ dailyChange / 100 }}&nbsp;
<template v-if="dailyChange > 0">
<el-image :src="upArrow" style="width: 14px;"/>
</template>
<template v-else-if="dailyChange < 0">
<el-image :src="downArrow" style="width: 14px;"/>
</template>
<template v-else>
<el-image :src="pingArrow" style="width: 14px; padding-top: 12px"/>
</template>
</div>
<div>
<el-row>
<!-- 左边文本信息 -->
<el-col :span="12">
<div class="margin-bottom" style="white-space: nowrap;">
永久金币:<b>{{ currentPermanent / 100 }}</b>
</div>
<div class="margin-bottom">&nbsp;</div>
<div class="margin-bottom">免费金币:{{ currentFree / 100 }}</div>
<!-- <div class="margin-bottom">&nbsp</div>-->
<!-- <div class="margin-bottom">&nbsp</div>-->
<div class="margin-bottom">
[6月到期:{{ currentFreeJune / 100 }}]
</div>
<div class="margin-bottom">&nbsp;</div>
<div class="margin-bottom">任务金币:{{ currentTask / 100 }}</div>
</el-col>
<!-- 右边图表 -->
<el-col :span="12">
<!-- <div ref="goldTypeChart" style="width: 100%; height: 100px;"></div>-->
<div style="width: 100%; height: 60px;">&nbsp;</div>
<div class="margin-bottom">
[12月到期:{{ currentFreeDecember / 100 }}]
</div>
</el-col>
</el-row>
</div>
</div>
</el-col>
<el-col :span="12">
<!-- 第二个卡片 -->
<div class="card-item-row1">
<div class="card-title">全年累计充值金币数{{ yearlyRecharge / 100 }}</div>
<el-row>
<el-col :span="12">
<div class="center-card">折合新币累计金额</div>
<el-image :src="svg1" style="width: 68px; display: block;margin: 0 auto;"/>
<div class="center-card">{{ yearlyMoney / 100 }}新币</div>
</el-col>
<el-col :span="12" style="border-left: 2px solid #CFE6FE; height: 120px">
<div class="center-card" style="white-space: nowrap;">昨日新增金币:{{ recharge / 100 }}</div>
<div ref="rechargeGoldChart" style="width: 68px; height: 68px; display: block;margin: 0 auto;"></div>
<div class="center-card" style="white-space: nowrap;">其中永久金币:{{ money / 100 }}</div>
</el-col>
</el-row>
</div>
</el-col>
</el-row>
<!-- 第二行:包含两个横向格子 -->
<el-row>
<el-col :span="12">
<!-- 第三个卡片 -->
<div class="card-item">
<div class="card-title">全年累计消费金币数{{ yearlyReduce / 100 }}</div>
<el-row style="height: 200px;">
<el-col :span="12">
<div ref="consumeChart" style="width:100%; height: 68%;"></div>
</el-col>
<el-col :span="12">
<div ref="consumeDetailChart" style="width: 100%; height: 88%;"></div>
</el-col>
</el-row>
</div>
</el-col>
<el-col :span="12">
<!-- 第四个卡片 -->
<div class="card-item">
<div class="card-title">全年累计充值人头数{{ yearlyRechargeNum }}</div>
<el-row style="height: 200px;">
<el-col :span="12" style="border-right: 2px solid #CFE6FE; height: 150px">
<div class="chart5">
<el-image :src="svg2" style="width: 68px; display: block;margin: 0 auto;"/>
<div class="margin-bottom">
<div style="display: flex; gap: 10px; font-size: 14px;">周同比:{{ sumWow }}%
<el-image v-if="sumWow > 0" :src="upArrow" style="width: 10px;"/>
<el-image v-else-if="sumWow < 0" :src="downArrow" style="width: 10px;"/>
<el-image v-else :src="pingArrow" style="width: 10px;"/>
</div>
<div style="display: flex; gap: 10px; font-size: 14px;">
日环比:{{ sumDaily }}%
<el-image v-if="sumDaily > 0" :src="upArrow" style="width: 10px;"/>
<el-image v-else-if="sumDaily < 0" :src="downArrow" style="width: 10px;"/>
<el-image v-else :src="pingArrow" style="width: 10px; "/>
</div>
</div>
</div>
</el-col>
<!-- 新增的环形图容器 -->
<el-col :span="12">
<div ref="rechargePeopleChart" style="width:100%; height: 68%;"></div>
</el-col>
</el-row>
</div>
</el-col>
</el-row>
</div>
</template>
<script setup>
import {onMounted, ref, nextTick} from 'vue'
import * as echarts from 'echarts'
import API from '@/util/http'
import dayjs from 'dayjs';
import utc from 'dayjs-plugin-utc'
import {ArrowDownBold, ArrowUpBold, SemiSelect} from '@element-plus/icons-vue'
import svg1 from '@/assets/SvgIcons/折合新币累计金额.svg'
import svg2 from '@/assets/SvgIcons/周同比.svg'
import upArrow from '@/assets/SvgIcons/上升箭头.svg'
import downArrow from '@/assets/SvgIcons/下降箭头.svg'
import pingArrow from '@/assets/SvgIcons/持平.svg'
dayjs.extend(utc)
// 用户信息
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 ydayRechargeNum = ref(0)
const firstRecharge = ref(0)
const length = ref(0)
// ECharts 实例引用
const goldTypeChart = ref(null)
const rechargeGoldChart = ref(null)
const consumeChart = ref(null)
const consumeDetailChart = ref(null)
const rechargePeopleChart = ref(null)
// 要加上所有市场的,还有额外计算的(总数 = 永久 + 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,
ydayRechargeNum: 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) {
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.toFixed(2)
dailyChange.value = summary.dailyChange.toFixed(2)
currentPermanent.value = summary.currentPermanent.toFixed(2)
currentFree.value = summary.currentFree.toFixed(2)
currentFreeJune.value = summary.currentFreeJune.toFixed(2)
currentFreeDecember.value = summary.currentFreeDecember.toFixed(2)
currentTask.value = summary.currentTask.toFixed(2)
yearlyRecharge.value = summary.yearlyRecharge.toFixed(2)
yearlyMoney.value = summary.yearlyMoney.toFixed(2)
recharge.value = summary.recharge.toFixed(2)
money.value = summary.money.toFixed(2)
yearlyReduce.value = summary.yearlyReduce.toFixed(2)
yearlyConsume.value = summary.yearlyConsume.toFixed(2)
yearlyRefund.value = summary.yearlyRefund.toFixed(2)
dailyReduce.value = summary.dailyReduce.toFixed(2)
dailyConsume.value = yesterdayConsume.toFixed(2)
dailyRefund.value = yesterdayRefund.toFixed(2)
yearlyRechargeNum.value = summary.yearlyRechargeNum
ydayRechargeNum.value = summary.ydayRechargeNum
firstRecharge.value = summary.firstRecharge
// 初始化图表
nextTick(() => {
// initGoldTypeChart();
initRechargeGoldChart();
initConsumeChart();
initConsumeDetailChart();
initRechargePeopleChart();
});
}
// 初始化金币类型南丁格尔图
const initGoldTypeChart = () => {
const myChart = echarts.init(goldTypeChart.value);
const option = {
tooltip: {
trigger: 'item',
formatter: function (params) {
let realValue = 0
if (params.name === '永久金币') realValue = currentPermanent.value / 100
else if (params.name === '免费金币') realValue = (currentFreeJune.value / 100 + currentFreeDecember.value / 100)
else realValue = currentTask.value / 100
return `${params.name}: ${realValue}`
}
},
toolbox: {
show: true,
feature: {}
},
series: [
{
name: 'Nightingale Chart',
type: 'pie',
radius: ['0%', '100%'],
center: ['50%', '50%'],
roseType: 'area',
itemStyle: {
borderRadius: 5
},
data: [
{value: Math.log(currentPermanent.value / 100 + 1), name: '永久金币'},
{value: Math.log((currentFreeJune.value / 100 + currentFreeDecember.value / 100) + 1), name: '免费金币'},
{value: Math.log(currentTask.value / 100 + 1), name: '任务金币'}
],
labelLine: {show: false},
label: {show: false}
}
]
};
myChart.setOption(option);
}
// 初始化充值金币环形图
const initRechargeGoldChart = () => {
const myChart = echarts.init(rechargeGoldChart.value);
const option = {
series: [
{
type: 'pie',
radius: ['60%', '85%'],
silent: true,
clockwise: true,
label: {show: false},
data: [
{
value: recharge.value / 100,
itemStyle: {color: '#80aaff'}
}
]
},
{
type: 'pie',
radius: ['60%', '75%'],
startAngle: 180,
silent: true,
clockwise: true,
label: {show: false},
data: [
{
value: money.value / 100,
itemStyle: {color: '#f2c97d'}
},
{
value: (recharge.value / 100 - money.value / 100),
itemStyle: {color: 'transparent'}
}
]
}
]
};
myChart.setOption(option);
}
// 初始化消费退款环形图
const initConsumeChart = () => {
const myChart = echarts.init(consumeChart.value);
const option = {
legend: {
orient: 'vertical',
left: '10%',
top: '85',
icon: 'circle',
iconSize: 5,
textSize: 12,
itemWidth: 7,
itemHeight: 7,
},
series: [
{
type: 'pie',
radius: ['30%', '45%'],
center: ['50%', '35%'],
silent: true,
clockwise: true,
label: {show: false},
data: [
{
value: yearlyConsume.value / 100,
name: '消耗:' + yearlyConsume.value / 100,
// name: '消耗:' + 1234567890,
itemStyle: {color: '#7DB7FA'}
},
{
value: yearlyRefund.value / 100,
name: '退款:' + yearlyRefund.value / 100,
itemStyle: {color: '#F7D47C'}
}
],
}
]
};
myChart.setOption(option);
};
// 初始化消费明细环形图
const initConsumeDetailChart = () => {
const myChart = echarts.init(consumeDetailChart.value);
const option = {
// 增加图表内边距,避免内容溢出
legend: {
orient: 'vertical',
left: '20%',
top: '85',
icon: 'circle',
iconSize: 5,
itemWidth: 7,
itemHeight: 7,
},
series: [
{
type: 'pie',
radius: ['25%', '40%'],
center: ['50%', '25%'],
silent: true,
clockwise: true,
label: {show: false},
data: [
{
value: dailyConsume.value / 100,
name: '昨日新增消费:' + dailyConsume.value / 100,
itemStyle: {color: '#65C9C9'}
}
]
},
{
type: 'pie',
radius: ['25%', '35%'],
center: ['50%', '25%'],
startAngle: 180,
silent: true,
clockwise: true,
label: {show: false},
data: [
{
value: dailyReduce.value / 100,
name: '昨日新增消耗:' + dailyReduce.value / 100,
// name: '昨日新增消耗:' + 1234567890,
itemStyle: {color: '#9469D1'}
},
{
value: dailyRefund.value / 100,
name: '昨日新增退款:' + dailyRefund.value / 100,
itemStyle: {color: '#B8DB6E'}
}
]
}
]
};
myChart.setOption(option);
};
// 初始化充值人头环形图
const initRechargePeopleChart = () => {
const myChart = echarts.init(rechargePeopleChart.value);
const option = {
legend: {
orient: 'vertical',
left: '20%',
top: '85',
icon: 'circle',
iconSize: 5,
textSize: 18,
itemWidth: 7,
itemHeight: 7,
},
series: [
{
type: 'pie',
radius: ['30%', '50%'],
center: ['50%', '35%'],
silent: true,
clockwise: true,
label: {show: false},
data: [
{
value: ydayRechargeNum.value,
name: '昨日充值人数:' + ydayRechargeNum.value,
itemStyle: {color: '#65C9C9'}
},
],
},
{
type: 'pie',
radius: ['30%', '45%'],
center: ['50%', '35%'],
silent: true,
clockwise: true,
label: {show: false},
data: [
{
value: firstRecharge.value,
name: '其中首充:' + firstRecharge.value,
itemStyle: {color: '#9469D1'}
},
{
value: ydayRechargeNum.value - firstRecharge.value,
itemStyle: {color: 'transparent'}
}
],
}
]
};
myChart.setOption(option);
}
// 获取卡片数据
const getCardData = async () => {
try {
const response = await API({url: '/workbench/getCard', data: {}})
workDataUpdateTime.value = response.updateTime
// 周同比
sumWow.value = response.sumWow.toFixed(2)
// 日环比
sumDaily.value = response.sumDaily.toFixed(2)
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)
}
}
const workDataUpdateTime = ref(null)
onMounted(async () => {
await getCardData()
})
</script>
<style scoped lang="scss">
.center-card {
display: flex;
justify-content: center;
align-items: center;
}
.card-item-row1 {
height: 160px;
width: auto;
background: #E4F0FC;
box-shadow: 0 0 4px 0 #00000040;
border-radius: 10px;
margin-top: 20px;
margin-left: 5px;
margin-right: 5px;
margin-bottom: -5px;
padding-bottom: 10px;
}
.card-item {
height: 200px;
width: auto;
background: #E4F0FC;
box-shadow: 0 0 4px 0 #00000040;
border-radius: 10px;
margin-top: 20px;
margin-left: 5px;
margin-right: 5px;
margin-bottom: -5px;
padding-bottom: 10px;
}
.card-title {
font-weight: bold;
height: 36px;
width: 100%;
flex-shrink: 0;
border-radius: 8px;
background: linear-gradient(90deg, #E4F0FC 0%, #C1DCF8 50%, #E4F0FC 100%);
box-shadow: 0 0 2px 0 #00152940;
display: flex;
align-items: center;
justify-content: center;
margin-top: -5px;
margin-bottom: 10px;
}
.card-item .el-col {
overflow: visible;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.gold-title {
width: 100%;
height: 5vh;
flex-shrink: 0;
border-radius: 8px;
background: linear-gradient(90deg, #E4F0FC 0%, #FFF178 50%, #E4F0FC 100%);
box-shadow: 0 2px 2px 0 #00152940;
display: flex;
align-items: center;
justify-content: center;
}
.text1 {
color: #040a2d;
font-family: " PingFang SC ";
font-size: 28px;
font-style: normal;
font-weight: 900;
line-height: 31.79px;
}
.text1-update-time {
width: 100%;
height: 26px;
flex-shrink: 0;
color: #040a2d;
font-family: "PingFang SC";
font-size: 20px;
font-style: normal;
font-weight: 700;
line-height: 31.79px;
}
/* 背景卡片大小 */
.gold-management {
margin: 10px 5px;
width: 100%;
height: 50vh;
flex-shrink: 0;
border-radius: 8px;
background: #E7F4FD;
box-shadow: 0 2px 2px 0 #00000040;
flex-direction: column;
align-items: center;
}
.margin-bottom {
padding-left: 20px;
}
.chart5 {
margin-top: 15px;
.margin-bottom {
margin-top: 10px;
padding-left: 20px;
}
}
</style>