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
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> 较前一日
|
|
{{ dailyChange / 100 }}
|
|
<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"> </div>
|
|
|
|
<div class="margin-bottom">免费金币:{{ currentFree / 100 }}</div>
|
|
<!-- <div class="margin-bottom"> </div>-->
|
|
<!-- <div class="margin-bottom"> </div>-->
|
|
<div class="margin-bottom">
|
|
[6月到期:{{ currentFreeJune / 100 }}]
|
|
</div>
|
|
<div class="margin-bottom"> </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;"> </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>
|