|
@ -1,7 +1,15 @@ |
|
|
<template> |
|
|
<template> |
|
|
<el-col :span="4"> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<el-row> |
|
|
|
|
|
<!-- 数据总览卡片 --> |
|
|
|
|
|
<el-col :span="4" style="padding-right: 10px;"> <!-- 适当留白避免拥挤 --> |
|
|
<el-card class="center-card margin-bottom">数据总览</el-card> |
|
|
<el-card class="center-card margin-bottom">数据总览</el-card> |
|
|
</el-col> |
|
|
</el-col> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 剩余栅格空间(可选,用于占满一行) --> |
|
|
|
|
|
<el-col :span="18"></el-col> |
|
|
|
|
|
</el-row> |
|
|
<el-row :gutter="10"> |
|
|
<el-row :gutter="10"> |
|
|
<!-- 第一个卡片 --> |
|
|
<!-- 第一个卡片 --> |
|
|
<el-col :span="6"> |
|
|
<el-col :span="6"> |
|
@ -9,21 +17,23 @@ |
|
|
<template #header> |
|
|
<template #header> |
|
|
<div class="card-header"> |
|
|
<div class="card-header"> |
|
|
<div class="card-title">当前金币余量</div> |
|
|
<div class="card-title">当前金币余量</div> |
|
|
<div>{{ currentGold / 100 }} 较前一日 {{ |
|
|
|
|
|
dailyChange / 100 }} |
|
|
|
|
|
|
|
|
<div>{{ currentGold / 100 }} 较前一日 |
|
|
|
|
|
{{ |
|
|
|
|
|
dailyChange / 100 |
|
|
|
|
|
}} |
|
|
<template v-if="dailyChange > 0"> |
|
|
<template v-if="dailyChange > 0"> |
|
|
<el-icon style="color:red"> |
|
|
<el-icon style="color:red"> |
|
|
<ArrowUpBold /> |
|
|
|
|
|
|
|
|
<ArrowUpBold/> |
|
|
</el-icon> |
|
|
</el-icon> |
|
|
</template> |
|
|
</template> |
|
|
<template v-else-if="dailyChange < 0"> |
|
|
<template v-else-if="dailyChange < 0"> |
|
|
<el-icon style="color:forestgreen"> |
|
|
<el-icon style="color:forestgreen"> |
|
|
<ArrowDownBold /> |
|
|
|
|
|
|
|
|
<ArrowDownBold/> |
|
|
</el-icon> |
|
|
</el-icon> |
|
|
</template> |
|
|
</template> |
|
|
<template v-else> |
|
|
<template v-else> |
|
|
<el-icon style="color:grey"> |
|
|
<el-icon style="color:grey"> |
|
|
<SemiSelect /> |
|
|
|
|
|
|
|
|
<SemiSelect/> |
|
|
</el-icon> |
|
|
</el-icon> |
|
|
</template> |
|
|
</template> |
|
|
</div> |
|
|
</div> |
|
@ -34,7 +44,9 @@ |
|
|
<div class="margin-bottom">免费金币:{{ currentFree / 100 }}</div> |
|
|
<div class="margin-bottom">免费金币:{{ currentFree / 100 }}</div> |
|
|
<div class="margin-bottom">[六月到期|{{ currentFreeJune / 100 }}] [12月到期|{{ |
|
|
<div class="margin-bottom">[六月到期|{{ currentFreeJune / 100 }}] [12月到期|{{ |
|
|
currentFreeDecember / |
|
|
currentFreeDecember / |
|
|
100 }}]</div> |
|
|
|
|
|
|
|
|
100 |
|
|
|
|
|
}}] |
|
|
|
|
|
</div> |
|
|
<div>任务金币:{{ currentTask / 100 }}</div> |
|
|
<div>任务金币:{{ currentTask / 100 }}</div> |
|
|
</div> |
|
|
</div> |
|
|
</el-card> |
|
|
</el-card> |
|
@ -57,14 +69,14 @@ |
|
|
<!-- 第三个卡片 --> |
|
|
<!-- 第三个卡片 --> |
|
|
<el-col :span="6"> |
|
|
<el-col :span="6"> |
|
|
<el-card class="card-item"> |
|
|
<el-card class="card-item"> |
|
|
<div class="card-title">全年累计消耗金币数</div> |
|
|
|
|
|
|
|
|
<div class="card-title">全年累计消费金币数</div> |
|
|
<div class="card-title">{{ yearlyReduce / 100 }}</div> |
|
|
<div class="card-title">{{ yearlyReduce / 100 }}</div> |
|
|
<div class="center-card">消费:{{ yearlyConsume / 100 }}</div> |
|
|
<div class="center-card">消费:{{ yearlyConsume / 100 }}</div> |
|
|
<div class="center-card">退款:{{ yearlyRefund / 100 }}</div> |
|
|
<div class="center-card">退款:{{ yearlyRefund / 100 }}</div> |
|
|
<template #footer> |
|
|
<template #footer> |
|
|
<div></div> |
|
|
<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">昨日新增消费:{{ dailyConsume / 100 }}</div> |
|
|
|
|
|
<div class="margin-bottom center-card">昨日新增消耗:{{ dailyReduce / 100 }}</div> |
|
|
<div class="margin-bottom center-card">昨日新增退款:{{ dailyRefund / 100 }}</div> |
|
|
<div class="margin-bottom center-card">昨日新增退款:{{ dailyRefund / 100 }}</div> |
|
|
</template> |
|
|
</template> |
|
|
</el-card> |
|
|
</el-card> |
|
@ -78,34 +90,34 @@ |
|
|
<el-col class="center-card">周同比:{{ sumWow }}% |
|
|
<el-col class="center-card">周同比:{{ sumWow }}% |
|
|
<template v-if="sumWow > 0"> |
|
|
<template v-if="sumWow > 0"> |
|
|
<el-icon style="color:red"> |
|
|
<el-icon style="color:red"> |
|
|
<ArrowUpBold /> |
|
|
|
|
|
|
|
|
<ArrowUpBold/> |
|
|
</el-icon> |
|
|
</el-icon> |
|
|
</template> |
|
|
</template> |
|
|
<template v-else-if="sumWow < 0"> |
|
|
<template v-else-if="sumWow < 0"> |
|
|
<el-icon style="color:forestgreen"> |
|
|
<el-icon style="color:forestgreen"> |
|
|
<ArrowDownBold /> |
|
|
|
|
|
|
|
|
<ArrowDownBold/> |
|
|
</el-icon> |
|
|
</el-icon> |
|
|
</template> |
|
|
</template> |
|
|
<template v-else> |
|
|
<template v-else> |
|
|
<el-icon style="color:grey"> |
|
|
<el-icon style="color:grey"> |
|
|
<SemiSelect /> |
|
|
|
|
|
|
|
|
<SemiSelect/> |
|
|
</el-icon> |
|
|
</el-icon> |
|
|
</template> |
|
|
</template> |
|
|
</el-col> |
|
|
</el-col> |
|
|
<el-col class="center-card">日环比:{{ sumDaily }}% |
|
|
<el-col class="center-card">日环比:{{ sumDaily }}% |
|
|
<template v-if="sumDaily > 0"> |
|
|
<template v-if="sumDaily > 0"> |
|
|
<el-icon style="color:red"> |
|
|
<el-icon style="color:red"> |
|
|
<ArrowUpBold /> |
|
|
|
|
|
|
|
|
<ArrowUpBold/> |
|
|
</el-icon> |
|
|
</el-icon> |
|
|
</template> |
|
|
</template> |
|
|
<template v-else-if="sumDaily < 0"> |
|
|
<template v-else-if="sumDaily < 0"> |
|
|
<el-icon style="color:forestgreen"> |
|
|
<el-icon style="color:forestgreen"> |
|
|
<ArrowDownBold /> |
|
|
|
|
|
|
|
|
<ArrowDownBold/> |
|
|
</el-icon> |
|
|
</el-icon> |
|
|
</template> |
|
|
</template> |
|
|
<template v-else> |
|
|
<template v-else> |
|
|
<el-icon style="color:grey"> |
|
|
<el-icon style="color:grey"> |
|
|
<SemiSelect /> |
|
|
|
|
|
|
|
|
<SemiSelect/> |
|
|
</el-icon> |
|
|
</el-icon> |
|
|
</template> |
|
|
</template> |
|
|
</el-col> |
|
|
</el-col> |
|
@ -130,11 +142,14 @@ |
|
|
<el-col :span="24"> |
|
|
<el-col :span="24"> |
|
|
<el-row> |
|
|
<el-row> |
|
|
<div style="margin-top:5px">合计 |
|
|
<div style="margin-top:5px">合计 |
|
|
永久金币 {{ activeTab === 'recharge' ? sumRechargePermanent / 100 : sumConsumePermanent / 100 |
|
|
|
|
|
|
|
|
永久金币 {{ |
|
|
|
|
|
activeTab === 'recharge' ? sumRechargePermanent / 100 : sumConsumePermanent / 100 |
|
|
}} |
|
|
}} |
|
|
免费金币 {{ activeTab === 'recharge' ? sumRechargeFree / 100 : sumConsumeFree / 100 |
|
|
|
|
|
|
|
|
免费金币 {{ |
|
|
|
|
|
activeTab === 'recharge' ? sumRechargeFree / 100 : sumConsumeFree / 100 |
|
|
}} |
|
|
}} |
|
|
任务金币 {{ activeTab === 'recharge' ? sumRechargeTask / 100 : sumConsumeTask / 100 |
|
|
|
|
|
|
|
|
任务金币 {{ |
|
|
|
|
|
activeTab === 'recharge' ? sumRechargeTask / 100 : sumConsumeTask / 100 |
|
|
}} |
|
|
}} |
|
|
</div> |
|
|
</div> |
|
|
<div> |
|
|
<div> |
|
@ -193,13 +208,14 @@ |
|
|
|
|
|
|
|
|
<script setup> |
|
|
<script setup> |
|
|
import * as echarts from 'echarts' |
|
|
import * as echarts from 'echarts' |
|
|
import { ref, onMounted, nextTick, watch } from 'vue' |
|
|
|
|
|
|
|
|
import {ref, onMounted, nextTick, watch} from 'vue' |
|
|
import API from '@/util/http' |
|
|
import API from '@/util/http' |
|
|
import { ElMessage } from 'element-plus' |
|
|
|
|
|
|
|
|
import {ElMessage} from 'element-plus' |
|
|
import dayjs from 'dayjs'; |
|
|
import dayjs from 'dayjs'; |
|
|
import utc from 'dayjs-plugin-utc' |
|
|
import utc from 'dayjs-plugin-utc' |
|
|
|
|
|
|
|
|
dayjs.extend(utc) |
|
|
dayjs.extend(utc) |
|
|
import { ArrowUpBold, ArrowDownBold, SemiSelect } from '@element-plus/icons-vue' |
|
|
|
|
|
|
|
|
import {ArrowUpBold, ArrowDownBold, SemiSelect, Refresh} from '@element-plus/icons-vue' |
|
|
// 地区数据 |
|
|
// 地区数据 |
|
|
const markets = ref([]) |
|
|
const markets = ref([]) |
|
|
// 图表相关 |
|
|
// 图表相关 |
|
@ -242,7 +258,8 @@ const sumDaily = ref(0) |
|
|
const rechargeNum = ref(0) |
|
|
const rechargeNum = ref(0) |
|
|
const firstRecharge = ref(0) |
|
|
const firstRecharge = ref(0) |
|
|
const length = ref(0) |
|
|
const length = ref(0) |
|
|
const formatDate = function(date) { |
|
|
|
|
|
|
|
|
const isLoading = ref(false) |
|
|
|
|
|
const formatDate = function (date) { |
|
|
const year = date.getFullYear(); |
|
|
const year = date.getFullYear(); |
|
|
const month = String(date.getMonth() + 1).padStart(2, '0'); |
|
|
const month = String(date.getMonth() + 1).padStart(2, '0'); |
|
|
const day = String(date.getDate()).padStart(2, '0'); |
|
|
const day = String(date.getDate()).padStart(2, '0'); |
|
@ -250,12 +267,12 @@ const formatDate = function(date) { |
|
|
const minutes = String(date.getMinutes()).padStart(2, '0'); |
|
|
const minutes = String(date.getMinutes()).padStart(2, '0'); |
|
|
const seconds = String(date.getSeconds()).padStart(2, '0'); |
|
|
const seconds = String(date.getSeconds()).padStart(2, '0'); |
|
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; |
|
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; |
|
|
} |
|
|
|
|
|
|
|
|
} |
|
|
// 今天 |
|
|
// 今天 |
|
|
const getToday = function () { |
|
|
const getToday = function () { |
|
|
const today = dayjs() |
|
|
const today = dayjs() |
|
|
const startTime = today.startOf('day').format('YYYY-MM-DD HH:mm:ss') |
|
|
const startTime = today.startOf('day').format('YYYY-MM-DD HH:mm:ss') |
|
|
const endTime = today.add(1,'day').startOf('day').format('YYYY-MM-DD HH:mm:ss') |
|
|
|
|
|
|
|
|
const endTime = today.add(1, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss') |
|
|
dateRange.value = [startTime, endTime] |
|
|
dateRange.value = [startTime, endTime] |
|
|
console.log('看看dateRange', dateRange.value) |
|
|
console.log('看看dateRange', dateRange.value) |
|
|
getChartData() |
|
|
getChartData() |
|
@ -263,8 +280,8 @@ const getToday = function () { |
|
|
// 本周 |
|
|
// 本周 |
|
|
const getWeek = function () { |
|
|
const getWeek = function () { |
|
|
const today = dayjs() |
|
|
const today = dayjs() |
|
|
const startTime = (today.startOf('week').add(1,'day')).format('YYYY-MM-DD HH:mm:ss') |
|
|
|
|
|
const endTime = today.add(1,'week').startOf('week').add(1,'day').format('YYYY-MM-DD HH:mm:ss') |
|
|
|
|
|
|
|
|
const startTime = (today.startOf('week').add(1, 'day')).format('YYYY-MM-DD HH:mm:ss') |
|
|
|
|
|
const endTime = today.add(1, 'week').startOf('week').add(1, 'day').format('YYYY-MM-DD HH:mm:ss') |
|
|
dateRange.value = [startTime, endTime] |
|
|
dateRange.value = [startTime, endTime] |
|
|
console.log('看看dateRange', dateRange.value) |
|
|
console.log('看看dateRange', dateRange.value) |
|
|
getChartData() |
|
|
getChartData() |
|
@ -273,7 +290,7 @@ const getWeek = function () { |
|
|
const getMonth = function () { |
|
|
const getMonth = function () { |
|
|
const today = dayjs() |
|
|
const today = dayjs() |
|
|
const startTime = today.startOf('month').format('YYYY-MM-DD HH:mm:ss') |
|
|
const startTime = today.startOf('month').format('YYYY-MM-DD HH:mm:ss') |
|
|
const endTime = today.add(1,'month').startOf('month').format('YYYY-MM-DD HH:mm:ss') |
|
|
|
|
|
|
|
|
const endTime = today.add(1, 'month').startOf('month').format('YYYY-MM-DD HH:mm:ss') |
|
|
dateRange.value = [startTime, endTime] |
|
|
dateRange.value = [startTime, endTime] |
|
|
console.log('看看dateRange', dateRange.value) |
|
|
console.log('看看dateRange', dateRange.value) |
|
|
getChartData() |
|
|
getChartData() |
|
@ -282,7 +299,7 @@ const getMonth = function () { |
|
|
const getYear = function () { |
|
|
const getYear = function () { |
|
|
const today = dayjs() |
|
|
const today = dayjs() |
|
|
const startTime = today.startOf('year').format('YYYY-MM-DD HH:mm:ss') |
|
|
const startTime = today.startOf('year').format('YYYY-MM-DD HH:mm:ss') |
|
|
const endTime = today.add(1,'year').startOf('year').format('YYYY-MM-DD HH:mm:ss') |
|
|
|
|
|
|
|
|
const endTime = today.add(1, 'year').startOf('year').format('YYYY-MM-DD HH:mm:ss') |
|
|
dateRange.value = [startTime, endTime] |
|
|
dateRange.value = [startTime, endTime] |
|
|
console.log('看看dateRange', dateRange.value) |
|
|
console.log('看看dateRange', dateRange.value) |
|
|
getChartData() |
|
|
getChartData() |
|
@ -369,7 +386,7 @@ const processData = (data) => { |
|
|
// 获取市场列表 |
|
|
// 获取市场列表 |
|
|
const getMarkets = async () => { |
|
|
const getMarkets = async () => { |
|
|
try { |
|
|
try { |
|
|
const response = await API({ url: '/general/market', data: {} }) |
|
|
|
|
|
|
|
|
const response = await API({url: '/general/market', data: {}}) |
|
|
if (Array.isArray(response.data)) { |
|
|
if (Array.isArray(response.data)) { |
|
|
markets.value = response.data |
|
|
markets.value = response.data |
|
|
console.log('市场列表获取成功:', markets.value) |
|
|
console.log('市场列表获取成功:', markets.value) |
|
@ -392,7 +409,7 @@ const getChartData = async () => { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 本年 |
|
|
// 本年 |
|
|
if(!dateRange.value || dateRange.value.length === 0){ |
|
|
|
|
|
|
|
|
if (!dateRange.value || dateRange.value.length === 0) { |
|
|
getYear() |
|
|
getYear() |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -542,7 +559,7 @@ const updateChart = (chartData) => { |
|
|
type: 'bar', |
|
|
type: 'bar', |
|
|
stack: 'recharge', |
|
|
stack: 'recharge', |
|
|
data: chartData.rechargePermanent, |
|
|
data: chartData.rechargePermanent, |
|
|
itemStyle: { color: '#5470c6' }, |
|
|
|
|
|
|
|
|
itemStyle: {color: '#5470c6'}, |
|
|
barWidth: 30 |
|
|
barWidth: 30 |
|
|
}, |
|
|
}, |
|
|
{ |
|
|
{ |
|
@ -550,7 +567,7 @@ const updateChart = (chartData) => { |
|
|
type: 'bar', |
|
|
type: 'bar', |
|
|
stack: 'recharge', |
|
|
stack: 'recharge', |
|
|
data: chartData.rechargeFree, |
|
|
data: chartData.rechargeFree, |
|
|
itemStyle: { color: '#91cc75' }, |
|
|
|
|
|
|
|
|
itemStyle: {color: '#91cc75'}, |
|
|
barWidth: 30 |
|
|
barWidth: 30 |
|
|
}, |
|
|
}, |
|
|
{ |
|
|
{ |
|
@ -558,7 +575,7 @@ const updateChart = (chartData) => { |
|
|
type: 'bar', |
|
|
type: 'bar', |
|
|
stack: 'recharge', |
|
|
stack: 'recharge', |
|
|
data: chartData.rechargeTask, |
|
|
data: chartData.rechargeTask, |
|
|
itemStyle: { color: '#fac858' }, |
|
|
|
|
|
|
|
|
itemStyle: {color: '#fac858'}, |
|
|
barWidth: 30 |
|
|
barWidth: 30 |
|
|
} |
|
|
} |
|
|
] |
|
|
] |
|
@ -570,7 +587,7 @@ const updateChart = (chartData) => { |
|
|
type: 'bar', |
|
|
type: 'bar', |
|
|
stack: 'consume', |
|
|
stack: 'consume', |
|
|
data: chartData.consumePermanent, |
|
|
data: chartData.consumePermanent, |
|
|
itemStyle: { color: '#5470c6' }, |
|
|
|
|
|
|
|
|
itemStyle: {color: '#5470c6'}, |
|
|
barWidth: 30 |
|
|
barWidth: 30 |
|
|
}, |
|
|
}, |
|
|
{ |
|
|
{ |
|
@ -578,7 +595,7 @@ const updateChart = (chartData) => { |
|
|
type: 'bar', |
|
|
type: 'bar', |
|
|
stack: 'consume', |
|
|
stack: 'consume', |
|
|
data: chartData.consumeFree, |
|
|
data: chartData.consumeFree, |
|
|
itemStyle: { color: '#91cc75' }, |
|
|
|
|
|
|
|
|
itemStyle: {color: '#91cc75'}, |
|
|
barWidth: 30 |
|
|
barWidth: 30 |
|
|
}, |
|
|
}, |
|
|
{ |
|
|
{ |
|
@ -586,7 +603,7 @@ const updateChart = (chartData) => { |
|
|
type: 'bar', |
|
|
type: 'bar', |
|
|
stack: 'consume', |
|
|
stack: 'consume', |
|
|
data: chartData.consumeTask, |
|
|
data: chartData.consumeTask, |
|
|
itemStyle: { color: '#fac858' }, |
|
|
|
|
|
|
|
|
itemStyle: {color: '#fac858'}, |
|
|
barWidth: 30 |
|
|
barWidth: 30 |
|
|
} |
|
|
} |
|
|
] |
|
|
] |
|
@ -648,7 +665,7 @@ const handleTabChange = () => { |
|
|
|
|
|
|
|
|
const getAdminData = async function () { |
|
|
const getAdminData = async function () { |
|
|
try { |
|
|
try { |
|
|
const result = await API({ url: '/admin/userinfo', data: {} }) |
|
|
|
|
|
|
|
|
const result = await API({url: '/admin/userinfo', data: {}}) |
|
|
adminData.value = result |
|
|
adminData.value = result |
|
|
console.log('用户信息', adminData.value) |
|
|
console.log('用户信息', adminData.value) |
|
|
} catch (error) { |
|
|
} catch (error) { |
|
@ -658,7 +675,7 @@ const getAdminData = async function () { |
|
|
// 获取卡片数据 |
|
|
// 获取卡片数据 |
|
|
const getCardData = async () => { |
|
|
const getCardData = async () => { |
|
|
try { |
|
|
try { |
|
|
const response = await API({ url: '/workbench/getCard', data: {} }) |
|
|
|
|
|
|
|
|
const response = await API({url: '/workbench/getCard', data: {}}) |
|
|
if (response && response.data) { |
|
|
if (response && response.data) { |
|
|
processData(response.data) |
|
|
processData(response.data) |
|
|
} else if (Array.isArray(response?.marketCards)) { |
|
|
} else if (Array.isArray(response?.marketCards)) { |
|
@ -671,6 +688,21 @@ const getCardData = async () => { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const refreshWorkspace = async () => { |
|
|
|
|
|
isLoading.value = true |
|
|
|
|
|
try { |
|
|
|
|
|
const result = await API({url: '/workbench/updateCard', data: {}}) |
|
|
|
|
|
if (result.code === 200) { |
|
|
|
|
|
ElMessage.success('数据更新成功') |
|
|
|
|
|
} else { |
|
|
|
|
|
ElMessage.error('数据更新失败') |
|
|
|
|
|
} |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error('刷新工作台失败:', error) |
|
|
|
|
|
} finally { |
|
|
|
|
|
isLoading.value = false |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
onMounted(async () => { |
|
|
onMounted(async () => { |
|
|
|
|
|
|
|
|