|
|
<template> <div class="gold-management"> <div class="gold-title"> <div class="text1"> {{ t('workbench.goldManagement') }} <span class="text1-update-time">{{ t('workbench.lastUpdateTime') }}{{ workDataUpdateTime && workDataUpdateTime !== '1970-01-01 08:00:00' ? workDataUpdateTime : t('workbench.noData') }} </span> </div> </div> <!-- 第一行:包含两个横向格子 --> <el-row> <el-col :span="12"> <!-- 第一个卡片 --> <div class="card-item-row1"> <div class="card-title"> {{ t('workbench.currentGoldBalance') }} <span style="font-weight: bold">{{ currentGold / 100 }}</span> {{ t('workbench.compareToPreviousDay') }} {{ dailyChange / 100 }} <template v-if="dailyChange > 0"> <el-image :src="upArrow" style="width: .7292vw;"/> </template> <template v-else-if="dailyChange < 0"> <el-image :src="downArrow" style="width: .7292vw;"/> </template> <template v-else> <el-image :src="pingArrow" style="width: .7292vw; padding-top: .625vw"/> </template> </div> <div> <el-row> <!-- 左边文本信息 --> <el-col :span="12"> <div class="margin-bottom" style="white-space: nowrap;"> {{ t('workbench.permanentGold') }}:<b>{{ currentPermanent / 100 }}</b> </div> <div class="margin-bottom"> </div>
<div class="margin-bottom">{{ t('workbench.freeGold') }}:<b>{{ currentFree / 100 }}</b></div> <!-- <div class="margin-bottom"> </div>--> <!-- <div class="margin-bottom"> </div>--> <div class="margin-bottom"> [{{ t('workbench.goldExpireIn6Months')}}{{ currentFreeJune / 100 }}] </div> <div class="margin-bottom"> </div>
<div class="margin-bottom">{{ t('workbench.taskGold') }}:<b>{{ currentTask / 100 }}</b></div> </el-col> <!-- 右边图表 --> <el-col :span="12"> <!-- <div ref="goldTypeChart" style="width: 100%; height: 5.2083vw;"></div>--> <div style="width: 100%; height: 3.125vw;"> </div> <div class="margin-bottom"> [{{ t('workbench.goldExpireIn12Months')}}{{ currentFreeDecember / 100 }}] </div> </el-col> </el-row> </div>
</div> </el-col> <el-col :span="12"> <!-- 第二个卡片 --> <div class="card-item-row1"> <div class="card-title">{{ t('workbench.annualCumulativeRecharge')}}{{ yearlyRecharge / 100 }}</div> <el-row> <el-col :span="12"> <div class="center-card">{{ t('workbench.convertedSGDCumulativeAmount') }}</div> <el-image :src="svg1" style="width: 4.5833vw; display: block;margin: 0 auto;"/> <div class="center-card">{{ yearlyMoney / 100 }}{{ t('workbench.SGD') }}</div> </el-col> <el-col :span="12" style="border-left: .1042vw solid #CFE6FE; height: 8.3333vw"> <div class="center-card" style="white-space: nowrap;">{{ t('workbench.yesterdayNew')}}{{ recharge / 100 }}</div> <div ref="rechargeGoldChart" style="width: 4.5833vw; height: 4.5833vw; display: block;margin: 0 auto;"></div> <div class="center-card" style="white-space: nowrap;">{{ t('workbench.wherePermanentGold')}}{{ 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">{{ t('workbench.annualCumulativeConsume')}}{{ yearlyReduce / 100 }}</div> <el-row style="height: 10.4167vw;"> <el-col :span="12"> <div ref="consumeChart" style="width:100%; height: 88%;"></div> </el-col> <el-col :span="12"> <div ref="consumeDetailChart" style="width: 100%; height: 108%;"></div> </el-col> </el-row> </div> </el-col> <el-col :span="12"> <!-- 第四个卡片 --> <div class="card-item" > <div class="card-title">{{ t('workbench.annualCumulativeRechargePeople')}}{{ yearlyRechargeNum }}</div> <el-row style="height: 10.4167vw;"> <el-col :span="12" style="border-right: .1042vw solid #CFE6FE; height: 10.4167vw"> <div class="chart5"> <el-image :src="svg2" style="width: 4.5833vw; display: block;margin: 0 auto;"/> <div class="margin-bottom"> <div style="display: flex; gap: .5208vw; font-size: .8333vw;">{{ t('workbench.weekYearOnYear')}}{{ sumWow }}% <el-image v-if="sumWow > 0" :src="upArrow" style="width: .5208vw;"/> <el-image v-else-if="sumWow < 0" :src="downArrow" style="width: .5208vw;"/> <el-image v-else :src="pingArrow" style="width: .5208vw;"/> </div> <div style="display: flex; gap: .5208vw; font-size: .8333vw;"> {{ t('workbench.dayYearOnYear')}}{{ sumDaily }}% <el-image v-if="sumDaily > 0" :src="upArrow" style="width: .5208vw;"/> <el-image v-else-if="sumDaily < 0" :src="downArrow" style="width: .5208vw;"/> <el-image v-else :src="pingArrow" style="width: .5208vw; "/> </div> </div>
</div>
</el-col> <!-- 新增的环形图容器 --> <el-col :span="12"> <div ref="rechargePeopleChart" style="width:100%; height: 88%;"></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/convert-singapore-total.svg'import svg2 from '@/assets/SvgIcons/wow.svg'import upArrow from '@/assets/SvgIcons/up-arrow.svg'import downArrow from '@/assets/SvgIcons/down-arrow.svg'import pingArrow from '@/assets/SvgIcons/unchanged.svg'import { useI18n } from 'vue-i18n'
const { t } = useI18n()
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: { textStyle: { fontSize: 15, color: '#000', fontFamily: 'PingFang SC' }, orient: 'vertical', left: '15%', top: '105', icon: 'circle', iconSize: 7, textSize: 12, itemWidth: 7, itemHeight: 7, },
series: [ { type: 'pie', radius: ['30%', '45%'], center: ['50%', '30%'], silent: true, clockwise: true, label: {show: false}, data: [ { value: yearlyConsume.value / 100, name: t('workbench.consume') + yearlyConsume.value / 100, // name: '消耗:' + 1234567890,
itemStyle: {color: '#7DB7FA'}
}, { value: yearlyRefund.value / 100, name: t('workbench.refund') + yearlyRefund.value / 100, itemStyle: {color: '#F7D47C'}
} ], } ] }; myChart.setOption(option);};// 初始化消费明细环形图
const initConsumeDetailChart = () => { const myChart = echarts.init(consumeDetailChart.value); const option = { // 增加图表内边距,避免内容溢出
legend: { textStyle: { fontSize: 15, color: '#000', fontFamily: 'PingFang SC' }, orient: 'vertical', left: '10%', top: '105', 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: t('workbench.yesterdayNewAll') + 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: t('workbench.yesterdayNewConsume') + dailyReduce.value / 100, // name: '昨日新增消耗:' + 1234567890,
itemStyle: {color: '#9469D1'} }, { value: dailyRefund.value / 100, name: t('workbench.yesterdayNewRefund') + dailyRefund.value / 100, itemStyle: {color: '#B8DB6E'} } ] } ] };
myChart.setOption(option);};// 初始化充值人头环形图
const initRechargePeopleChart = () => { const myChart = echarts.init(rechargePeopleChart.value); const option = { legend: { textStyle: { fontSize: 15, color: '#000', fontFamily: 'PingFang SC' }, orient: 'vertical', left: '20%', top: '110', icon: 'circle', iconSize: 5, itemWidth: 7, itemHeight: 7, }, series: [ { type: 'pie', radius: ['30%', '50%'], center: ['50%', '30%'], silent: true, clockwise: true, label: {show: false}, data: [ { value: ydayRechargeNum.value, name: t('workbench.yesterdayRechargePeople') + ydayRechargeNum.value, itemStyle: {color: '#65C9C9'} }, ], }, { type: 'pie', radius: ['30%', '45%'], center: ['50%', '30%'], silent: true, clockwise: true, label: {show: false}, data: [ { value: firstRecharge.value, name: t('workbench.whereFirstRecharge') + 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: 10.4167vw; width: auto; background: #E4F0FC; box-shadow: 0 0 .2083vw 0 #00000040; border-radius: .5208vw; margin-top: 1.0417vw; margin-left: .2604vw; margin-right: .2604vw; margin-bottom: -0.2604vw; padding-bottom: .5208vw;}
.card-item { height: 12.5vw; width: auto; background: #E4F0FC; box-shadow: 0 0 .2083vw 0 #00000040; border-radius: .5208vw; margin-top: 1.0417vw; margin-left: .2604vw; margin-right: .2604vw; margin-bottom: -0.2604vw; padding-bottom: .5208vw;}
.card-title { font-weight: bold; height: 1.875vw; font-size: .8854vw; width: 100%; flex-shrink: 0; border-radius: .4167vw; background: linear-gradient(90deg, #E4F0FC 0%, #C1DCF8 50%, #E4F0FC 100%); box-shadow: 0 0 .1042vw 0 #00152940; display: flex; align-items: center; justify-content: center; margin-top: -0.2604vw; margin-bottom: .5208vw;}
.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: .4167vw; background: linear-gradient(90deg, #E4F0FC 0%, #FFF178 50%, #E4F0FC 100%); box-shadow: 0 .1042vw .1042vw 0 #00152940; display: flex; align-items: center; justify-content: center;}
.text1 { color: #040a2d; font-family: " PingFang SC "; font-size: 1.4583vw; font-style: normal; font-weight: 900; line-height: 1.6557vw;}
.text1-update-time { width: 100%; height: 1.3542vw; flex-shrink: 0; color: #040a2d; font-family: "PingFang SC"; font-size: 1.0417vw; font-style: normal; font-weight: 700; line-height: 1.6557vw;}
/* 背景卡片大小 */.gold-management { margin: .5208vw .2604vw; width: 100%; height: 28.6458vw; flex-shrink: 0; border-radius: .4167vw; background: #E7F4FD; box-shadow: 0 .1042vw .1042vw 0 #00000040; flex-direction: column; align-items: center;}
.margin-bottom { padding-left: 1.0417vw;}
.chart5 { margin-top: .7813vw;
.margin-bottom { margin-top: .5208vw; padding-left: 1.0417vw; }}</style>
|