Browse Source
Merge branch 'milestone-20250913-现金管理' of http://39.101.133.168:8807/huangqizhen/gold-vue into zhangyong/milestone-20250913-现金管理
zhangyong/milestone-20250913-现金管理
Merge branch 'milestone-20250913-现金管理' of http://39.101.133.168:8807/huangqizhen/gold-vue into zhangyong/milestone-20250913-现金管理
zhangyong/milestone-20250913-现金管理
25 changed files with 2007 additions and 341 deletions
-
14src/components/workspace/CashManagement.vue
-
210src/components/workspace/CashManagementMarkets.vue
-
94src/components/workspace/GoldGraph.vue
-
818src/components/workspace/GoldGraphMarkets.vue
-
10src/components/workspace/GoldManagement.vue
-
142src/views/audit/bean/beanAudit.vue
-
49src/views/audit/gold/rechargeAudit.vue
-
49src/views/audit/gold/refundAudit.vue
-
53src/views/consume/bean/articleVideo.vue
-
51src/views/consume/bean/dieHardFan.vue
-
51src/views/consume/bean/liveStream.vue
-
52src/views/consume/gold/coinConsumeDetail.vue
-
41src/views/moneyManage/receiveDetail/receiveDetail.vue
-
39src/views/permissions/rolePermission.vue
-
37src/views/permissions/userPermission.vue
-
2src/views/recharge/bean/addBeanRecharge.vue
-
52src/views/recharge/bean/beanOnlineRecharge.vue
-
54src/views/recharge/bean/beanSystemRecharge.vue
-
20src/views/recharge/gold/addCoinRecharge.vue
-
50src/views/recharge/gold/coinRechargeDetail.vue
-
51src/views/refund/gold/coinRefundDetail.vue
-
51src/views/usergold/bean/userbean.vue
-
234src/views/usergold/gold/clientCountBalance.vue
-
51src/views/usergold/gold/clientCountDetail.vue
-
73src/views/workspace/index.vue
@ -0,0 +1,210 @@ |
|||||
|
<!--各地区的现金管理情况--> |
||||
|
<template> |
||||
|
|
||||
|
<div class="cash-management"> |
||||
|
<div class="cash-title"> |
||||
|
<div class="text1"> 现金管理 |
||||
|
<span class="text1-update-time">最后更新时间:{{ |
||||
|
workDataUpdateTime && workDataUpdateTime !== '1970-01-01 08:00:00' ? workDataUpdateTime : '该地区暂无数据' |
||||
|
}}</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="text2"><span class="text2-income">总营收:{{ cashData.totalIncome }}</span></div> |
||||
|
|
||||
|
|
||||
|
<div class="chart-container"> |
||||
|
<!-- 左侧数据列表 --> |
||||
|
<div class="market-data"> |
||||
|
<div v-for="market in cashData.markets" :key="market.name" class="market-item"> |
||||
|
<span class="market-name">{{ market.name }}:</span> |
||||
|
<span class="market-value">{{ market.value.toLocaleString() }}</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 图表区域 --> |
||||
|
<div ref="chartRef" class="chart"></div> |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import * as echarts from 'echarts' |
||||
|
import {ref, onMounted} from 'vue' |
||||
|
|
||||
|
// 模拟数据 |
||||
|
const cashData = ref({ |
||||
|
updateTime: '2025-09-24 12:00:00', |
||||
|
totalIncome: 1200000, |
||||
|
markets: [ |
||||
|
{name: '北京', value: 450000}, |
||||
|
{name: '上海', value: 300000}, |
||||
|
{name: '广州', value: 200000}, |
||||
|
{name: '深圳', value: 150000}, |
||||
|
{name: '其他', value: 100000} |
||||
|
] |
||||
|
}) |
||||
|
|
||||
|
const chartRef = ref(null) |
||||
|
let chartInstance = null |
||||
|
|
||||
|
const renderChart = () => { |
||||
|
if (!chartInstance && chartRef.value) { |
||||
|
chartInstance = echarts.init(chartRef.value) |
||||
|
} |
||||
|
const option = { |
||||
|
tooltip: {trigger: 'item'}, |
||||
|
legend: { |
||||
|
bottom: 5, // 增加底部距离的 |
||||
|
left: 'center' |
||||
|
}, |
||||
|
series: [ |
||||
|
{ |
||||
|
label: {show: false}, |
||||
|
|
||||
|
type: 'pie', |
||||
|
radius: ['40%', '70%'], |
||||
|
data: cashData.value.markets, |
||||
|
center: ['60%', '45%'] //图表靠右一点 |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
chartInstance.setOption(option) |
||||
|
} |
||||
|
|
||||
|
onMounted(() => { |
||||
|
renderChart() |
||||
|
}) |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
/* 背景卡片大小 */ |
||||
|
.cash-management { |
||||
|
margin: 10px 5px; |
||||
|
width: 100%; |
||||
|
height: 50vh; |
||||
|
flex-shrink: 0; |
||||
|
border-radius: 8px; |
||||
|
background: #E7F4FD; |
||||
|
box-shadow: 0 2px 2px 0 #00000040; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
align-items: center; |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
.cash-card { |
||||
|
width: 100%; |
||||
|
} |
||||
|
|
||||
|
.chart { |
||||
|
width: 100%; |
||||
|
height: 200px; |
||||
|
} */ |
||||
|
|
||||
|
|
||||
|
.cash-title { |
||||
|
width: 100%; |
||||
|
height: 5vh; |
||||
|
flex-shrink: 0; |
||||
|
border-radius: 8px; |
||||
|
background: linear-gradient(90deg, #E4F0FC 0%, #C6ADFF 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; |
||||
|
} |
||||
|
|
||||
|
/* 总收入的渐变框 */ |
||||
|
.text2 { |
||||
|
margin: 13px; |
||||
|
width: 95%; |
||||
|
height: 48px; |
||||
|
flex-shrink: 0; |
||||
|
border-radius: 8px; |
||||
|
background: linear-gradient(90deg, #E4F0FC 0%, #C1DCF8 50%, #E4F0FC 100%); |
||||
|
box-shadow: 0 2px 2px 0 #00152940; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
} |
||||
|
|
||||
|
/* 总收入字体 */ |
||||
|
.text2-income { |
||||
|
width: 215px; |
||||
|
height: 26px; |
||||
|
flex-shrink: 0; |
||||
|
color: #040a2d; |
||||
|
font-family: "PingFang SC"; |
||||
|
font-size: 20px; |
||||
|
font-style: normal; |
||||
|
font-weight: 900; |
||||
|
line-height: 31.79px; |
||||
|
} |
||||
|
|
||||
|
/* 图表容器 */ |
||||
|
.chart-container { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
padding: 10px; |
||||
|
} |
||||
|
|
||||
|
/* 左侧数据列表,使用您指定的样式 */ |
||||
|
.market-data { |
||||
|
display: flex; |
||||
|
width: 179px; |
||||
|
flex-direction: column; |
||||
|
align-items: flex-start; |
||||
|
gap: 12px; |
||||
|
padding: 10px; |
||||
|
margin-left: 80px; |
||||
|
} |
||||
|
|
||||
|
.market-item { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
width: 100%; |
||||
|
font-family: "PingFang SC"; |
||||
|
font-size: 16px; |
||||
|
color: #040a2d; |
||||
|
} |
||||
|
|
||||
|
.market-name { |
||||
|
font-weight: 700; |
||||
|
} |
||||
|
|
||||
|
.market-value { |
||||
|
font-weight: 500; |
||||
|
} |
||||
|
|
||||
|
/* 图表样式 */ |
||||
|
.chart { |
||||
|
flex: 1; |
||||
|
height: 300px; |
||||
|
margin-top: 10px; |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,818 @@ |
|||||
|
<!--各地区的金币充值和消费情况柱状图--> |
||||
|
|
||||
|
<template> |
||||
|
<div class="graph"> |
||||
|
<el-card style="width:100%;" class="graph-card"> |
||||
|
<div> |
||||
|
<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> |
||||
|
</div> |
||||
|
<div class="condition"> |
||||
|
<div class="stats"> |
||||
|
<div v-if="activeTab === 'consume'">合计:{{ sumConsume / 100 }}</div> |
||||
|
永久金币: {{ activeTab === 'recharge' ? sumRechargePermanent / 100 : sumConsumePermanent / 100 }} |
||||
|
免费金币: {{ activeTab === 'recharge' ? sumRechargeFree / 100 : sumConsumeFree / 100 }} |
||||
|
任务金币: {{ activeTab === 'recharge' ? sumRechargeTask / 100 : sumConsumeTask / 100 }} |
||||
|
</div> |
||||
|
<div> |
||||
|
<el-button @click="getYes()" size="small" :type="activeTimeRange === 'yes' ? 'primary' : ''">昨天 |
||||
|
</el-button> |
||||
|
<el-button @click="getToday()" size="small" :type="activeTimeRange === 'today' ? 'primary' : ''">今天 |
||||
|
</el-button> |
||||
|
<el-button @click="getWeek()" size="small" :type="activeTimeRange === 'week' ? 'primary' : ''">本周 |
||||
|
</el-button> |
||||
|
<el-button @click="getMonth()" size="small" :type="activeTimeRange === 'month' ? 'primary' : ''">本月 |
||||
|
</el-button> |
||||
|
<el-button @click="getYear()" size="small" :type="activeTimeRange === 'year' ? 'primary' : ''">本年 |
||||
|
</el-button> |
||||
|
</div> |
||||
|
<div> |
||||
|
<el-date-picker size="small" v-model="dateRange" type="datetimerange" range-separator="→" |
||||
|
start-placeholder="开始时间" end-placeholder="结束时间" format="YYYY-MM-DD HH:mm:ss" |
||||
|
style="width:20vw;margin-left:0.5vw;" value-format="YYYY-MM-DD HH:mm:ss" |
||||
|
:default-time="defaultTime" |
||||
|
:disabled-date="disabledDate" @change="handleDatePickerChange"/> |
||||
|
<el-button type="primary" size="small" style="margin-left: 0.5vw" @click="getChartData">查询</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="graph-content"> |
||||
|
<div ref="chartRef" class="left"></div> |
||||
|
<div class="right"> |
||||
|
<el-card class="graph-card-list"> |
||||
|
<div class="card-large">金币{{ activeTab === 'recharge' ? '充值' : '消费' }}排名</div> |
||||
|
<el-select class="card-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 class="card-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"> |
||||
|
<template #default="scope"> |
||||
|
<span>{{ marketMapping[scope.row.market] || scope.row.market }}</span> |
||||
|
</template> |
||||
|
</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> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-card> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import * as echarts from 'echarts' |
||||
|
import {onMounted, onUnmounted, ref, watch} from 'vue' |
||||
|
import API from '@/util/http' |
||||
|
import {ElMessage} from 'element-plus' |
||||
|
import dayjs from 'dayjs'; |
||||
|
import utc from 'dayjs-plugin-utc' |
||||
|
import {marketMapping} from "@/utils/marketMap.js"; |
||||
|
|
||||
|
dayjs.extend(utc) |
||||
|
|
||||
|
const defaultTime = [ |
||||
|
new Date(2000, 1, 1, 0, 0, 0), |
||||
|
new Date(2000, 2, 1, 23, 59, 59), |
||||
|
] |
||||
|
|
||||
|
// 地区数据 |
||||
|
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 sumConsume = 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 ydayRechargeNum = ref(0) |
||||
|
const firstRecharge = ref(0) |
||||
|
const length = ref(0) |
||||
|
// 加载状态 |
||||
|
const chartLoading = ref(true) |
||||
|
|
||||
|
const handleResize = () => { |
||||
|
if (chartInstance.value) { |
||||
|
try { |
||||
|
chartInstance.value.resize() |
||||
|
console.log('resize一下') |
||||
|
} catch (error) { |
||||
|
console.error('图表resize失败:', error) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
// 初始化图表 |
||||
|
const initChart = () => { |
||||
|
if (!chartInstance && chartRef.value) { |
||||
|
chartInstance = echarts.init(chartRef.value) |
||||
|
window.addEventListener('resize', handleResize) |
||||
|
} |
||||
|
} |
||||
|
// 销毁图表 |
||||
|
const destroyChart = () => { |
||||
|
if (chartInstance.value) { |
||||
|
try { |
||||
|
chartInstance.value.dispose() |
||||
|
} catch (error) { |
||||
|
console.error('图表销毁失败:', error) |
||||
|
} |
||||
|
chartInstance.value = null |
||||
|
} |
||||
|
window.removeEventListener('resize', handleResize) |
||||
|
} |
||||
|
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 getYes = function () { |
||||
|
const yesterday = dayjs().subtract(1, 'day') |
||||
|
const startTime = yesterday.startOf('day').format('YYYY-MM-DD HH:mm:ss') |
||||
|
const endTime = yesterday.endOf('day').format('YYYY-MM-DD HH:mm:ss') |
||||
|
dateRange.value = [startTime, endTime] |
||||
|
console.log('看看dateRange', dateRange.value) |
||||
|
activeTimeRange.value = 'yes' // 标记当前激活状态 |
||||
|
|
||||
|
getChartData() |
||||
|
} |
||||
|
// 今天 |
||||
|
const getToday = function () { |
||||
|
const today = dayjs() |
||||
|
const startTime = today.startOf('day').format('YYYY-MM-DD HH:mm:ss') |
||||
|
const endTime = today.endOf('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] |
||||
|
console.log('看看dateRange', dateRange.value) |
||||
|
activeTimeRange.value = 'today' // 标记当前激活状态 |
||||
|
|
||||
|
getChartData() |
||||
|
} |
||||
|
// 本周 |
||||
|
const getWeek = function () { |
||||
|
const today = dayjs(); |
||||
|
// 获取今天是星期几(0是周日,1是周一,...,6是周六) |
||||
|
const day = today.day(); |
||||
|
|
||||
|
// 计算本周一(如果今天是周一,就取今天;如果是周日,就减6天) |
||||
|
let monday = today.subtract(day === 0 ? 6 : day - 1, 'day'); |
||||
|
// 计算本周日(如果今天是周日,就取今天;否则就加(7 - day)天) |
||||
|
let sunday = today.add(day === 0 ? 0 : 7 - day, 'day'); |
||||
|
|
||||
|
// 设置时间为起始和结束 |
||||
|
const startTime = monday.startOf('day').format('YYYY-MM-DD HH:mm:ss'); |
||||
|
const endTime = sunday.endOf('day').format('YYYY-MM-DD HH:mm:ss'); |
||||
|
|
||||
|
dateRange.value = [startTime, endTime]; |
||||
|
console.log('本周时间范围(周一到周日):', dateRange.value); |
||||
|
activeTimeRange.value = 'week'; |
||||
|
|
||||
|
getChartData(); |
||||
|
}; |
||||
|
// 本月 |
||||
|
const getMonth = function () { |
||||
|
const today = dayjs() |
||||
|
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.endOf('month').format('YYYY-MM-DD HH:mm:ss') |
||||
|
dateRange.value = [startTime, endTime] |
||||
|
console.log('看看dateRange', dateRange.value) |
||||
|
activeTimeRange.value = 'month' // 标记当前激活状态 |
||||
|
|
||||
|
getChartData() |
||||
|
} |
||||
|
// 本年 |
||||
|
const getYear = function () { |
||||
|
const today = dayjs() |
||||
|
const startTime = today.startOf('year').format('YYYY-MM-DD HH:mm:ss') |
||||
|
const endTime = today.endOf('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] |
||||
|
console.log('看看dateRange', dateRange.value) |
||||
|
activeTimeRange.value = 'year' // 标记当前激活状态 |
||||
|
|
||||
|
getChartData() |
||||
|
} |
||||
|
|
||||
|
// 要加上所有市场的,还有额外计算的(总数 = 永久 + 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) { // 其实还应该卡一个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.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 |
||||
|
|
||||
|
// // 周同比 |
||||
|
// sumWow.value = (marketCards.sumWow / length.value).toFixed(2) |
||||
|
// // 日环比 |
||||
|
// sumDaily.value = (marketCards.sumDaily / length.value).toFixed(2) |
||||
|
|
||||
|
// rechargeNum.value = summary.rechargeNum |
||||
|
ydayRechargeNum.value = summary.ydayRechargeNum |
||||
|
firstRecharge.value = summary.firstRecharge |
||||
|
} |
||||
|
|
||||
|
//无法选择的时间 |
||||
|
const disabledDate = (time) => { |
||||
|
const limitDate = new Date(2025, 0, 1); |
||||
|
return time.getTime() < limitDate.getTime(); |
||||
|
} |
||||
|
|
||||
|
// 获取市场列表 |
||||
|
const getMarkets = async () => { |
||||
|
console.log("adminData", adminData.value.account) |
||||
|
try { |
||||
|
const response = await API({ |
||||
|
url: '/general/adminMarkets', |
||||
|
data: { |
||||
|
account: adminData.value.account |
||||
|
} |
||||
|
}) |
||||
|
if (Array.isArray(response.data)) { |
||||
|
// markets.value = response.data.filter(data => data !== "1") |
||||
|
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() |
||||
|
} |
||||
|
// 本年 |
||||
|
if (!dateRange.value || dateRange.value.length === 0) { |
||||
|
getYear() |
||||
|
} |
||||
|
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)) { |
||||
|
// const filteredGraphs = response.marketGraphs.filter(data => data.market !== "1"); |
||||
|
// 处理图表数据 |
||||
|
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: [], |
||||
|
sumConsume: [] |
||||
|
} |
||||
|
// 这是图表的合计数,怎样遍历????? |
||||
|
const sumRechargePermanent1 = ref(0) |
||||
|
const sumRechargeFree1 = ref(0) |
||||
|
const sumRechargeTask1 = ref(0) |
||||
|
const sumConsumePermanent1 = ref(0) |
||||
|
const sumConsumeFree1 = ref(0) |
||||
|
const sumConsumeTask1 = ref(0) |
||||
|
const sumConsume1 = 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) |
||||
|
chartData.sumConsume.push(market.sumConsume / 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) |
||||
|
sumConsume1.value += (market.sumConsume || 0) |
||||
|
}) |
||||
|
sumRechargePermanent.value = sumRechargePermanent1.value |
||||
|
sumRechargeFree.value = sumRechargeFree1.value |
||||
|
sumRechargeTask.value = 0 |
||||
|
sumConsumePermanent.value = sumConsumePermanent1.value |
||||
|
sumConsumeFree.value = sumConsumeFree1.value |
||||
|
sumConsumeTask.value = sumConsumeTask1.value |
||||
|
sumConsume.value = sumConsume1.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, |
||||
|
coinAmount: coinAmount |
||||
|
}; |
||||
|
}); |
||||
|
|
||||
|
// 按金币数量排序 |
||||
|
rankingData.sort((a, b) => b.coinAmount - a.coinAmount); |
||||
|
|
||||
|
// 排名序号 |
||||
|
tableData.value = rankingData.map((item, index) => ({ |
||||
|
rank: index + 1, |
||||
|
...item |
||||
|
})); |
||||
|
} |
||||
|
|
||||
|
watch(selectedType, () => { |
||||
|
getChartData(); |
||||
|
}); |
||||
|
// 更新图表 |
||||
|
const updateChart = (chartData) => { |
||||
|
if (!chartInstance) { |
||||
|
initChart() |
||||
|
} |
||||
|
chartLoading.value = true |
||||
|
try { |
||||
|
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/>' |
||||
|
let total = 0; |
||||
|
params.forEach(param => { |
||||
|
result += `${param.seriesName}: ${param.value.toLocaleString()}<br/>`; |
||||
|
total += param.value; |
||||
|
}) |
||||
|
result += `总${activeTab.value === 'recharge' ? '充值' : '消费'}: ${total.toLocaleString()}`; |
||||
|
return result |
||||
|
} |
||||
|
}, |
||||
|
legend: { |
||||
|
data: legend, |
||||
|
bottom: 10 |
||||
|
}, |
||||
|
grid: { |
||||
|
left: '3%', |
||||
|
right: '4%', |
||||
|
bottom: '10%', |
||||
|
containLabel: true |
||||
|
}, |
||||
|
xAxis: { |
||||
|
type: 'category', |
||||
|
// 横坐标数据 之后要改成一个时间的 |
||||
|
data: markets.value, |
||||
|
axisLabel: { |
||||
|
interval: 0, |
||||
|
rotate: 0 |
||||
|
} |
||||
|
}, |
||||
|
yAxis: { |
||||
|
type: 'value', |
||||
|
splitLine: { |
||||
|
lineStyle: { |
||||
|
type: 'dashed', |
||||
|
width: 1, |
||||
|
color: '#000000' |
||||
|
} |
||||
|
}, |
||||
|
axisLabel: { |
||||
|
formatter: function (value) { |
||||
|
return value.toLocaleString() |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
}, |
||||
|
series: series, |
||||
|
// dataZoom: [ |
||||
|
// { |
||||
|
// type: 'slider', |
||||
|
// show: true, |
||||
|
// start: 0, |
||||
|
// end: 100, |
||||
|
// maxSpan: 100, |
||||
|
// minSpan: 100, |
||||
|
// |
||||
|
// height: 2, |
||||
|
// }, |
||||
|
// ] |
||||
|
} |
||||
|
|
||||
|
chartInstance.setOption(option) |
||||
|
} catch (error) { |
||||
|
console.error('图表更新失败:', error) |
||||
|
ElMessage.error('图表渲染失败') |
||||
|
} finally { |
||||
|
setTimeout(() => { |
||||
|
chartLoading.value = false |
||||
|
}, 300) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 处理标签切换 |
||||
|
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 activeTimeRange = ref('') |
||||
|
// 日期选择器变化时清除按钮激活状态 |
||||
|
const handleDatePickerChange = () => { |
||||
|
activeTimeRange.value = '' |
||||
|
} |
||||
|
|
||||
|
onMounted(async () => { |
||||
|
await getAdminData() |
||||
|
await getMarkets() |
||||
|
getYear() |
||||
|
window.addEventListener('resize', () => { |
||||
|
chartInstance.resize() |
||||
|
}) |
||||
|
}) |
||||
|
onUnmounted(() => { |
||||
|
destroyChart() |
||||
|
}) |
||||
|
</script> |
||||
|
<style scoped lang="scss"> |
||||
|
|
||||
|
|
||||
|
.graph { |
||||
|
.condition { |
||||
|
width: 100%; |
||||
|
height: 1%; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
|
||||
|
.stats { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
width: 35vw; |
||||
|
font-size: 15px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.graph-content { |
||||
|
flex: 1; |
||||
|
height: auto; |
||||
|
display: flex; |
||||
|
|
||||
|
.left { |
||||
|
width: 70%; |
||||
|
height: auto; |
||||
|
} |
||||
|
|
||||
|
.right { |
||||
|
flex: 1; |
||||
|
padding: 0.5vw 2vh; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.center-card { |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
} |
||||
|
|
||||
|
.margin-bottom { |
||||
|
margin-bottom: 0.5vh; |
||||
|
} |
||||
|
|
||||
|
.card-item { |
||||
|
width: 25%; |
||||
|
height: 28vh; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
justify-content: center; |
||||
|
margin-right: 0.25vw; |
||||
|
} |
||||
|
|
||||
|
.card-title { |
||||
|
font-weight: bold; |
||||
|
margin-bottom: 1vh; |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
} |
||||
|
|
||||
|
.card-large { |
||||
|
font-weight: bold; |
||||
|
font-size: 16px; |
||||
|
text-align: center; |
||||
|
margin-bottom: 15px; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
@keyframes spin { |
||||
|
0% { |
||||
|
transform: rotate(0deg); |
||||
|
} |
||||
|
|
||||
|
100% { |
||||
|
transform: rotate(360deg); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.graph-card { |
||||
|
background: #F3FAFF; |
||||
|
box-shadow: 0 0 8px 0 #00000040; |
||||
|
} |
||||
|
|
||||
|
.graph-card-list { |
||||
|
background: #F3FAFF; |
||||
|
box-shadow: 0 0 8px 0 #00000040; |
||||
|
padding: 12px; |
||||
|
|
||||
|
.card-select { |
||||
|
:deep(.el-input__wrapper) { |
||||
|
background-color: #E7F4FD !important; |
||||
|
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25) !important; |
||||
|
border: none !important; |
||||
|
} |
||||
|
|
||||
|
:deep(.el-input__inner) { |
||||
|
background-color: transparent !important; |
||||
|
} |
||||
|
|
||||
|
:deep(.el-input__suffix) { |
||||
|
background-color: transparent !important; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* 表格整体背景:把表格容器设为卡片背景 */ |
||||
|
:deep(.el-table) { |
||||
|
background-color: #F3FAFF !important; |
||||
|
box-shadow: none !important; |
||||
|
} |
||||
|
|
||||
|
/* 表头/表体 wrapper 与 table body 单元格 */ |
||||
|
:deep(.el-table__header-wrapper), |
||||
|
:deep(.el-table__body-wrapper), |
||||
|
:deep(.el-table__body), |
||||
|
:deep(.el-table__header), |
||||
|
:deep(.el-table__body tbody), |
||||
|
:deep(.el-table__body tr), |
||||
|
:deep(.el-table__row), |
||||
|
:deep(.el-table__cell), |
||||
|
:deep(.el-table__body td) { |
||||
|
background-color: transparent !important; |
||||
|
} |
||||
|
|
||||
|
/* 表头 */ |
||||
|
:deep(.el-table__header th) { |
||||
|
background-color: #F3FAFF !important; |
||||
|
} |
||||
|
|
||||
|
/* 行之间的分隔线(更像卡片内表格) */ |
||||
|
:deep(.el-table .el-table__row):not(:last-child) { |
||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.06); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
</style> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue