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.

881 lines
26 KiB

2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
4 months ago
2 months ago
4 months ago
2 months ago
2 months ago
2 months ago
3 months ago
3 months ago
3 months ago
3 months ago
2 months ago
2 months ago
4 months ago
4 months ago
4 months ago
4 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
2 months ago
3 months ago
3 months ago
2 months ago
4 months ago
4 months ago
3 months ago
3 months ago
3 months ago
4 months ago
2 months ago
4 months ago
4 months ago
2 months ago
4 months ago
2 months ago
4 months ago
2 months ago
4 months ago
4 months ago
4 months ago
3 months ago
3 months ago
  1. <template>
  2. <div class="top">
  3. <el-card style="width:20%" class="center-card">数据总览</el-card>
  4. <span class="text">
  5. 最后更新时间{{
  6. workDataUpdateTime && workDataUpdateTime !== '1970-01-01 08:00:00' ? workDataUpdateTime : '该地区暂无数据'
  7. }}
  8. </span>
  9. </div>
  10. <div class="card">
  11. <!-- 第一个卡片 -->
  12. <el-card class="card-item">
  13. <template #header>
  14. <div class="card-title">当前金币余量</div>
  15. <div>
  16. <span style="font-weight: bold">{{ currentGold / 100
  17. }}</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;较前一日
  18. {{ dailyChange / 100 }}
  19. <template v-if="dailyChange > 0">
  20. <el-icon style="color:red">
  21. <ArrowUpBold />
  22. </el-icon>
  23. </template>
  24. <template v-else-if="dailyChange < 0">
  25. <el-icon style="color:forestgreen">
  26. <ArrowDownBold />
  27. </el-icon>
  28. </template>
  29. <template v-else>
  30. <el-icon style="color:grey">
  31. <SemiSelect />
  32. </el-icon>
  33. </template>
  34. </div>
  35. </template>
  36. <div>
  37. <div class="margin-bottom">永久金币{{ currentPermanent / 100 }}</div>
  38. <div class="margin-bottom">免费金币{{ currentFree / 100 }}</div>
  39. <div class="margin-bottom">[六月到期|{{ currentFreeJune / 100 }}]&nbsp;&nbsp;
  40. [十二月到期|{{ currentFreeDecember / 100 }}]
  41. </div>
  42. <div>任务金币{{ currentTask / 100 }}</div>
  43. </div>
  44. </el-card>
  45. <!-- 第二个卡片 -->
  46. <el-card class="card-item">
  47. <div class="card-title">全年累计充值金币数</div>
  48. <div class="card-title">{{ yearlyRecharge / 100 }}</div>
  49. <div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
  50. <div class="center-card">折合新币累计金额:{{ yearlyMoney / 100 }}</div>
  51. <template #footer>
  52. <el-col class="margin-bottom center-card">昨日新增{{ recharge / 100 }}</el-col>
  53. <el-col class="margin-bottom center-card">其中充值{{ money / 100 }}</el-col>
  54. </template>
  55. </el-card>
  56. <!-- 第三个卡片 -->
  57. <el-card class="card-item">
  58. <div class="card-title">全年累计消费金币数</div>
  59. <div class="card-title">{{ yearlyReduce / 100 }}</div>
  60. <div class="center-card">消费{{ yearlyConsume / 100 }}</div>
  61. <div class="center-card">退款{{ yearlyRefund / 100 }}</div>
  62. <template #footer>
  63. <div></div>
  64. <div class="margin-bottom center-card">昨日新增消费{{ dailyConsume / 100 }}</div>
  65. <div class="margin-bottom center-card">昨日新增消耗{{ dailyReduce / 100 }}</div>
  66. <div class="margin-bottom center-card">昨日新增退款{{ dailyRefund / 100 }}</div>
  67. </template>
  68. </el-card>
  69. <!-- 第四个卡片 -->
  70. <el-card class="card-item">
  71. <el-col class="card-title">全年累计充值人头数</el-col>
  72. <el-col class="card-title">{{ yearlyRechargeNum }}</el-col>
  73. <el-col class="center-card">周同比:{{ sumWow }}%&nbsp;&nbsp;&nbsp;&nbsp;
  74. <template v-if="sumWow > 0">
  75. <el-icon style="color:red">
  76. <ArrowUpBold />
  77. </el-icon>
  78. </template>
  79. <template v-else-if="sumWow < 0">
  80. <el-icon style="color:forestgreen">
  81. <ArrowDownBold />
  82. </el-icon>
  83. </template>
  84. <template v-else>
  85. <el-icon style="color:grey">
  86. <SemiSelect />
  87. </el-icon>
  88. </template>
  89. </el-col>
  90. <el-col class="center-card">日环比:{{ sumDaily }}%&nbsp;&nbsp;&nbsp;&nbsp;
  91. <template v-if="sumDaily > 0">
  92. <el-icon style="color:red">
  93. <ArrowUpBold />
  94. </el-icon>
  95. </template>
  96. <template v-else-if="sumDaily < 0">
  97. <el-icon style="color:forestgreen">
  98. <ArrowDownBold />
  99. </el-icon>
  100. </template>
  101. <template v-else>
  102. <el-icon style="color:grey">
  103. <SemiSelect />
  104. </el-icon>
  105. </template>
  106. </el-col>
  107. <template #footer>
  108. <el-col class="margin-bottom center-card">昨日充值人数{{ ydayRechargeNum }}</el-col>
  109. <el-col class="margin-bottom center-card">其中首充{{ firstRecharge }}</el-col>
  110. </template>
  111. </el-card>
  112. </div>
  113. <div class="graph">
  114. <el-card style="width:100%;">
  115. <div>
  116. <el-tabs v-model="activeTab" @tab-change="handleTabChange">
  117. <el-tab-pane label="金币充值" name="recharge"></el-tab-pane>
  118. <el-tab-pane label="金币消费" name="consume"></el-tab-pane>
  119. </el-tabs>
  120. </div>
  121. <div class="condition">
  122. <div>合计&nbsp;
  123. 永久金币 {{ activeTab === 'recharge' ? sumRechargePermanent / 100 : sumConsumePermanent / 100 }}&nbsp;&nbsp;
  124. 免费金币 {{ activeTab === 'recharge' ? sumRechargeFree / 100 : sumConsumeFree / 100 }}&nbsp;&nbsp;
  125. 任务金币 {{ activeTab === 'recharge' ? sumRechargeTask / 100 : sumConsumeTask / 100 }}
  126. </div>
  127. <div @change="handleDatePickerChange" style="margin-left:auto;margin-right: 0.5%;">
  128. <el-button @click="getYes()" :type="activeTimeRange === 'yes' ? 'primary' : ''">昨天
  129. </el-button>
  130. <el-button @click="getToday()" :type="activeTimeRange === 'today' ? 'primary' : ''">今天
  131. </el-button>
  132. <el-button @click="getWeek()" :type="activeTimeRange === 'week' ? 'primary' : ''">本周
  133. </el-button>
  134. <el-button @click="getMonth()" :type="activeTimeRange === 'month' ? 'primary' : ''">本月
  135. </el-button>
  136. <el-button @click="getYear()" :type="activeTimeRange === 'year' ? 'primary' : ''">本年
  137. </el-button>
  138. </div>
  139. <div>
  140. <el-date-picker v-model="dateRange" type="datetimerange" range-separator="" start-placeholder="开始时间"
  141. end-placeholder="结束时间" format="YYYY-MM-DD HH:mm:ss" style="width:20vw" value-format="YYYY-MM-DD HH:mm:ss"
  142. :default-time="defaultTime" :disabled-date="disabledDate" />
  143. <el-button type="primary" style="margin-left: 5px" @click="getChartData">查询</el-button>
  144. </div>
  145. </div>
  146. <div class="graph-content">
  147. <div ref="chartRef" class="left"></div>
  148. <div class="right">
  149. <el-card>
  150. <div class="card-large">金币{{ activeTab === 'recharge' ? '充值' : '消费' }}排名</div>
  151. <el-select v-model="selectedType" style="width: 100%; margin-bottom: 15px">
  152. <el-option label="全部类型" value="all"></el-option>
  153. <el-option label="永久金币" value="permanent"></el-option>
  154. <el-option label="免费金币" value="free"></el-option>
  155. <el-option label="任务金币" value="task"></el-option>
  156. </el-select>
  157. <el-table :data="tableData" height="320px">
  158. <el-table-column prop="rank" label="排名" width="60" align="center"></el-table-column>
  159. <el-table-column prop="market" label="地区" align="center">
  160. <template #default="scope">
  161. <span>{{ marketMapping[scope.row.market] || scope.row.market }}</span>
  162. </template>
  163. </el-table-column>
  164. <el-table-column prop="coinAmount" label="金币数量" align="center">
  165. <template #default="{ row }">
  166. {{ row.coinAmount.toLocaleString() }}
  167. </template>
  168. </el-table-column>
  169. </el-table>
  170. </el-card>
  171. </div>
  172. </div>
  173. </el-card>
  174. </div>
  175. </template>
  176. <script setup>
  177. import * as echarts from 'echarts'
  178. import { ref, onMounted, nextTick, watch, onUnmounted } from 'vue'
  179. import API from '@/util/http'
  180. import { ElMessage } from 'element-plus'
  181. import dayjs from 'dayjs';
  182. import utc from 'dayjs-plugin-utc'
  183. dayjs.extend(utc)
  184. import { ArrowUpBold, ArrowDownBold, SemiSelect } from '@element-plus/icons-vue'
  185. import { marketMapping } from "@/utils/marketMap.js";
  186. const defaultTime = [
  187. new Date(2000, 1, 1, 0, 0, 0),
  188. new Date(2000, 2, 1, 23, 59, 59),
  189. ]
  190. // 地区数据
  191. const markets = ref([])
  192. // 图表相关
  193. const dateRange = ref([])
  194. const activeTab = ref('recharge')
  195. const selectedType = ref('all')
  196. const tableData = ref([])
  197. const chartRef = ref(null)
  198. let chartInstance = null
  199. // 图表合计数
  200. const sumRechargePermanent = ref(0)
  201. const sumRechargeFree = ref(0)
  202. const sumRechargeTask = ref(0)
  203. const sumConsumePermanent = ref(0)
  204. const sumConsumeFree = ref(0)
  205. const sumConsumeTask = ref(0)
  206. // 用户信息
  207. const adminData = ref({})
  208. // 卡片数据相关
  209. const currentGold = ref(0)
  210. const dailyChange = ref(0)
  211. const currentPermanent = ref(0)
  212. const currentFree = ref(0)
  213. const currentFreeJune = ref(0)
  214. const currentFreeDecember = ref(0)
  215. const currentTask = ref(0)
  216. const yearlyRecharge = ref(0)
  217. const yearlyMoney = ref(0)
  218. const recharge = ref(0)
  219. const money = ref(0)
  220. const yearlyReduce = ref(0)
  221. const yearlyConsume = ref(0)
  222. const yearlyRefund = ref(0)
  223. const dailyReduce = ref(0)
  224. const dailyConsume = ref(0)
  225. const dailyRefund = ref(0)
  226. const yearlyRechargeNum = ref(0)
  227. const sumWow = ref(0)
  228. const sumDaily = ref(0)
  229. const rechargeNum = ref(0)
  230. const ydayRechargeNum = ref(0)
  231. const firstRecharge = ref(0)
  232. const length = ref(0)
  233. // 加载状态
  234. const chartLoading = ref(true)
  235. const handleResize = () => {
  236. if (chartInstance.value) {
  237. try {
  238. chartInstance.value.resize()
  239. console.log('resize一下')
  240. } catch (error) {
  241. console.error('图表resize失败:', error)
  242. }
  243. }
  244. }
  245. // 初始化图表
  246. const initChart = () => {
  247. if (!chartInstance && chartRef.value) {
  248. chartInstance = echarts.init(chartRef.value)
  249. window.addEventListener('resize', handleResize)
  250. }
  251. }
  252. // 销毁图表
  253. const destroyChart = () => {
  254. if (chartInstance.value) {
  255. try {
  256. chartInstance.value.dispose()
  257. } catch (error) {
  258. console.error('图表销毁失败:', error)
  259. }
  260. chartInstance.value = null
  261. }
  262. window.removeEventListener('resize', handleResize)
  263. }
  264. const formatDate = function (date) {
  265. const year = date.getFullYear();
  266. const month = String(date.getMonth() + 1).padStart(2, '0');
  267. const day = String(date.getDate()).padStart(2, '0');
  268. const hours = String(date.getHours()).padStart(2, '0');
  269. const minutes = String(date.getMinutes()).padStart(2, '0');
  270. const seconds = String(date.getSeconds()).padStart(2, '0');
  271. return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
  272. }
  273. // 昨天
  274. const getYes = function () {
  275. const yesterday = dayjs().subtract(1, 'day')
  276. const startTime = yesterday.startOf('day').format('YYYY-MM-DD HH:mm:ss')
  277. const endTime = yesterday.endOf('day').format('YYYY-MM-DD HH:mm:ss')
  278. dateRange.value = [startTime, endTime]
  279. console.log('看看dateRange', dateRange.value)
  280. activeTimeRange.value = 'yes' // 标记当前激活状态
  281. getChartData()
  282. }
  283. // 今天
  284. const getToday = function () {
  285. const today = dayjs()
  286. const startTime = today.startOf('day').format('YYYY-MM-DD HH:mm:ss')
  287. const endTime = today.endOf('day').format('YYYY-MM-DD HH:mm:ss')
  288. // const endTime = today.add(1, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss')
  289. dateRange.value = [startTime, endTime]
  290. console.log('看看dateRange', dateRange.value)
  291. activeTimeRange.value = 'today' // 标记当前激活状态
  292. getChartData()
  293. }
  294. // 本周
  295. const getWeek = function () {
  296. const today = dayjs()
  297. const startTime = ((today.startOf('week').add(1, 'day')).format('YYYY-MM-DD HH:mm:ss'))
  298. const endTime = (today.endOf('week').add(1, 'day')).format('YYYY-MM-DD HH:mm:ss')
  299. // const endTime = today.add(1, 'week').startOf('week').add(1, 'day').format('YYYY-MM-DD HH:mm:ss')
  300. dateRange.value = [startTime, endTime]
  301. console.log('看看dateRange', dateRange.value)
  302. activeTimeRange.value = 'week' // 标记当前激活状态
  303. getChartData()
  304. }
  305. // 本月
  306. const getMonth = function () {
  307. const today = dayjs()
  308. const startTime = today.startOf('month').format('YYYY-MM-DD HH:mm:ss')
  309. // const endTime = today.add(1, 'month').startOf('month').format('YYYY-MM-DD HH:mm:ss')
  310. const endTime = today.endOf('month').format('YYYY-MM-DD HH:mm:ss')
  311. dateRange.value = [startTime, endTime]
  312. console.log('看看dateRange', dateRange.value)
  313. activeTimeRange.value = 'month' // 标记当前激活状态
  314. getChartData()
  315. }
  316. // 本年
  317. const getYear = function () {
  318. const today = dayjs()
  319. const startTime = today.startOf('year').format('YYYY-MM-DD HH:mm:ss')
  320. const endTime = today.endOf('year').format('YYYY-MM-DD HH:mm:ss')
  321. // const endTime = today.add(1, 'year').startOf('year').format('YYYY-MM-DD HH:mm:ss')
  322. dateRange.value = [startTime, endTime]
  323. console.log('看看dateRange', dateRange.value)
  324. activeTimeRange.value = 'year' // 标记当前激活状态
  325. getChartData()
  326. }
  327. // 要加上所有市场的,还有额外计算的(总数 = 永久 + 6月 + 12月 + 免费 + 任务)
  328. const processData = (data) => {
  329. const summary = {
  330. currentGold: 0,
  331. dailyChange: 0,
  332. currentPermanent: 0,
  333. currentFreeJune: 0,
  334. currentFreeDecember: 0,
  335. currentTask: 0,
  336. currentFree: 0,
  337. recharge: 0,
  338. money: 0,
  339. yearlyRecharge: 0,
  340. yearlyMoney: 0,
  341. consumePermanent: 0,
  342. consumeFreeJune: 0,
  343. consumeFreeDecember: 0,
  344. consumeTask: 0,
  345. refundPermanent: 0,
  346. refundFreeJune: 0,
  347. refundFreeDecember: 0,
  348. refundTask: 0,
  349. dailyReduce: 0,
  350. yearlyConsume: 0,
  351. yearlyRefund: 0,
  352. yearlyReduce: 0,
  353. rechargeNum: 0,
  354. ydayRechargeNum: 0,
  355. firstRecharge: 0,
  356. sumWow: 0,
  357. sumDaily: 0,
  358. yearlyRechargeNum: 0
  359. }
  360. // 遍历市场
  361. data.marketCards.forEach(market => {
  362. for (const i in summary) {
  363. if (market[i] !== undefined && market[i] !== null) { // 其实还应该卡一个number
  364. summary[i] += market[i]
  365. }
  366. }
  367. })
  368. // wow和daily除一下
  369. length.value = data.markets.length
  370. console.log(length.value)
  371. // 计算昨日新增消费和退款
  372. const yesterdayConsume = summary.consumePermanent + summary.consumeFreeJune + summary.consumeFreeDecember + summary.consumeTask
  373. const yesterdayRefund = summary.refundPermanent + summary.refundFreeJune + summary.refundFreeDecember + summary.refundTask
  374. // 更新卡片数据
  375. currentGold.value = summary.currentGold.toFixed(2)
  376. dailyChange.value = summary.dailyChange.toFixed(2)
  377. currentPermanent.value = summary.currentPermanent.toFixed(2)
  378. currentFree.value = summary.currentFree.toFixed(2)
  379. currentFreeJune.value = summary.currentFreeJune.toFixed(2)
  380. currentFreeDecember.value = summary.currentFreeDecember.toFixed(2)
  381. currentTask.value = summary.currentTask.toFixed(2)
  382. yearlyRecharge.value = summary.yearlyRecharge.toFixed(2)
  383. yearlyMoney.value = summary.yearlyMoney.toFixed(2)
  384. recharge.value = summary.recharge.toFixed(2)
  385. money.value = summary.money.toFixed(2)
  386. yearlyReduce.value = summary.yearlyReduce.toFixed(2)
  387. yearlyConsume.value = summary.yearlyConsume.toFixed(2)
  388. yearlyRefund.value = summary.yearlyRefund.toFixed(2)
  389. dailyReduce.value = summary.dailyReduce.toFixed(2)
  390. dailyConsume.value = yesterdayConsume.toFixed(2)
  391. dailyRefund.value = yesterdayRefund.toFixed(2)
  392. yearlyRechargeNum.value = summary.yearlyRechargeNum
  393. // // 周同比
  394. // sumWow.value = (marketCards.sumWow / length.value).toFixed(2)
  395. // // 日环比
  396. // sumDaily.value = (marketCards.sumDaily / length.value).toFixed(2)
  397. // rechargeNum.value = summary.rechargeNum
  398. ydayRechargeNum.value = summary.ydayRechargeNum
  399. firstRecharge.value = summary.firstRecharge
  400. }
  401. //无法选择的时间
  402. const disabledDate = (time) => {
  403. const limitDate = new Date(2025, 0, 1);
  404. return time.getTime() < limitDate.getTime();
  405. }
  406. // 获取市场列表
  407. const getMarkets = async () => {
  408. console.log("adminData", adminData.value.account)
  409. try {
  410. const response = await API({
  411. url: '/general/adminMarkets',
  412. data: {
  413. account: adminData.value.account
  414. }
  415. })
  416. if (Array.isArray(response.data)) {
  417. // markets.value = response.data.filter(data => data !== "1")
  418. markets.value = response.data
  419. console.log('市场列表获取成功:', markets.value)
  420. } else {
  421. console.error('获取市场列表失败', response)
  422. ElMessage.error('获取市场列表失败')
  423. }
  424. } catch (error) {
  425. console.error('获取市场列表失败:', error)
  426. ElMessage.error('获取市场列表失败')
  427. }
  428. }
  429. // 获取图表数据
  430. const getChartData = async () => {
  431. try {
  432. // 校验市场数据到底有没有
  433. if (!markets.value || markets.value.length === 0) {
  434. await getMarkets()
  435. }
  436. // 本年
  437. if (!dateRange.value || dateRange.value.length === 0) {
  438. getYear()
  439. }
  440. const params = {
  441. markets: markets.value,
  442. startDate: dateRange.value[0],
  443. endDate: dateRange.value[1]
  444. };
  445. const response = await API({
  446. url: '/workbench/getGraph',
  447. data: params
  448. })
  449. console.log('看看params', params)
  450. if (Array.isArray(response.marketGraphs)) {
  451. // const filteredGraphs = response.marketGraphs.filter(data => data.market !== "1");
  452. // 处理图表数据
  453. processChartData(response.marketGraphs)
  454. // 处理排名数据
  455. processRankingData(response.marketGraphs)
  456. } else {
  457. console.error('获取图表数据失败:', response)
  458. ElMessage.error('获取图表数据失败')
  459. }
  460. } catch (error) {
  461. console.error('获取图表数据失败:', error)
  462. ElMessage.error('获取图表数据失败')
  463. }
  464. }
  465. // 处理图表数据
  466. const processChartData = (marketCards) => {
  467. const chartData = {
  468. rechargePermanent: [],
  469. rechargeFree: [],
  470. rechargeTask: [],
  471. consumePermanent: [],
  472. consumeFree: [],
  473. consumeTask: []
  474. }
  475. // 这是图表的合计数,怎样遍历?????
  476. const sumRechargePermanent1 = ref(0)
  477. const sumRechargeFree1 = ref(0)
  478. const sumRechargeTask1 = ref(0)
  479. const sumConsumePermanent1 = ref(0)
  480. const sumConsumeFree1 = ref(0)
  481. const sumConsumeTask1 = ref(0)
  482. marketCards.forEach(market => {
  483. chartData.rechargePermanent.push(market.sumRechargePermanent / 100 || 0)
  484. chartData.rechargeFree.push(market.sumRechargeFree / 100 || 0)
  485. chartData.rechargeTask.push(market.sumRechargeTask / 100 || 0)
  486. chartData.consumePermanent.push(market.sumConsumePermanent / 100 || 0)
  487. chartData.consumeFree.push(market.sumConsumeFree / 100 || 0)
  488. chartData.consumeTask.push(market.sumConsumeTask / 100 || 0)
  489. // 合计数合计数合计数咋算
  490. sumRechargePermanent1.value += (market.sumRechargePermanent || 0)
  491. sumRechargeFree1.value += (market.sumRechargeFree || 0)
  492. //sumRechargeTask1.value += (market.sumRechargeTask || 0)
  493. sumConsumePermanent1.value += (market.sumConsumePermanent || 0)
  494. sumConsumeFree1.value += (market.sumConsumeFree || 0)
  495. sumConsumeTask1.value += (market.sumConsumeTask || 0)
  496. })
  497. sumRechargePermanent.value = sumRechargePermanent1.value
  498. sumRechargeFree.value = sumRechargeFree1.value
  499. sumRechargeTask.value = 0
  500. sumConsumePermanent.value = sumConsumePermanent1.value
  501. sumConsumeFree.value = sumConsumeFree1.value
  502. sumConsumeTask.value = sumConsumeTask1.value
  503. updateChart(chartData)
  504. }
  505. const processRankingData = (marketCards) => {
  506. // 每个市场的总金币数
  507. const rankingData = marketCards.map(market => {
  508. let coinAmount = 0;
  509. if (activeTab.value === 'recharge') {
  510. // 充值排名
  511. switch (selectedType.value) {
  512. case 'all':
  513. coinAmount = (market.sumRechargePermanent / 100 || 0) + (market.sumRechargeFree / 100 || 0) + (market.sumRechargeTask / 100 || 0);
  514. break;
  515. case 'permanent':
  516. coinAmount = market.sumRechargePermanent / 100 || 0;
  517. break;
  518. case 'free':
  519. coinAmount = market.sumRechargeFree / 100 || 0;
  520. break;
  521. case 'task':
  522. coinAmount = market.sumRechargeTask / 100 || 0;
  523. break;
  524. }
  525. } else {
  526. // 消费排名
  527. switch (selectedType.value) {
  528. case 'all':
  529. coinAmount = (market.sumConsumePermanent / 100 || 0) + (market.sumConsumeFree / 100 || 0) + (market.sumConsumeTask / 100 || 0);
  530. break;
  531. case 'permanent':
  532. coinAmount = market.sumConsumePermanent / 100 || 0;
  533. break;
  534. case 'free':
  535. coinAmount = market.sumConsumeFree / 100 || 0;
  536. break;
  537. case 'task':
  538. coinAmount = market.sumConsumeTask / 100 || 0;
  539. break;
  540. }
  541. }
  542. return {
  543. market: market.market,
  544. coinAmount: coinAmount
  545. };
  546. });
  547. // 按金币数量排序
  548. rankingData.sort((a, b) => b.coinAmount - a.coinAmount);
  549. // 排名序号
  550. tableData.value = rankingData.map((item, index) => ({
  551. rank: index + 1,
  552. ...item
  553. }));
  554. }
  555. watch(selectedType, () => {
  556. getChartData();
  557. });
  558. // 更新图表
  559. const updateChart = (chartData) => {
  560. if (!chartInstance) {
  561. initChart()
  562. }
  563. chartLoading.value = true
  564. try {
  565. let series = []
  566. let legend = []
  567. if (activeTab.value === 'recharge') {
  568. series = [
  569. {
  570. name: '永久金币',
  571. type: 'bar',
  572. stack: 'recharge',
  573. data: chartData.rechargePermanent,
  574. itemStyle: { color: '#5470c6' },
  575. barWidth: 30
  576. },
  577. {
  578. name: '免费金币',
  579. type: 'bar',
  580. stack: 'recharge',
  581. data: chartData.rechargeFree,
  582. itemStyle: { color: '#91cc75' },
  583. barWidth: 30
  584. },
  585. {
  586. name: '任务金币',
  587. type: 'bar',
  588. stack: 'recharge',
  589. data: chartData.rechargeTask,
  590. itemStyle: { color: '#fac858' },
  591. barWidth: 30
  592. }
  593. ]
  594. legend = ['永久金币', '免费金币', '任务金币']
  595. } else {
  596. series = [
  597. {
  598. name: '永久金币',
  599. type: 'bar',
  600. stack: 'consume',
  601. data: chartData.consumePermanent,
  602. itemStyle: { color: '#5470c6' },
  603. barWidth: 30
  604. },
  605. {
  606. name: '免费金币',
  607. type: 'bar',
  608. stack: 'consume',
  609. data: chartData.consumeFree,
  610. itemStyle: { color: '#91cc75' },
  611. barWidth: 30
  612. },
  613. {
  614. name: '任务金币',
  615. type: 'bar',
  616. stack: 'consume',
  617. data: chartData.consumeTask,
  618. itemStyle: { color: '#fac858' },
  619. barWidth: 30
  620. }
  621. ]
  622. legend = ['永久金币', '免费金币', '任务金币']
  623. }
  624. const option = {
  625. tooltip: {
  626. trigger: 'axis',
  627. axisPointer: {
  628. type: 'shadow'
  629. },
  630. formatter: function (params) {
  631. let result = params[0].name + '<br/>'
  632. params.forEach(param => {
  633. result += `${param.seriesName}: ${param.value.toLocaleString()}<br/>`
  634. })
  635. return result
  636. }
  637. },
  638. legend: {
  639. data: legend,
  640. bottom: 10
  641. },
  642. grid: {
  643. left: '3%',
  644. right: '4%',
  645. bottom: '15%',
  646. containLabel: true
  647. },
  648. xAxis: {
  649. type: 'category',
  650. data: markets.value,
  651. axisLabel: {
  652. interval: 0,
  653. rotate: 30
  654. }
  655. },
  656. yAxis: {
  657. type: 'value',
  658. axisLabel: {
  659. formatter: function (value) {
  660. return value.toLocaleString()
  661. }
  662. }
  663. },
  664. series: series,
  665. // dataZoom: [
  666. // {
  667. // type: 'slider',
  668. // show: true,
  669. // start: 0,
  670. // end: 100,
  671. // maxSpan: 100,
  672. // minSpan: 100,
  673. //
  674. // height: 2,
  675. // },
  676. // ]
  677. }
  678. chartInstance.setOption(option)
  679. } catch (error) {
  680. console.error('图表更新失败:', error)
  681. ElMessage.error('图表渲染失败')
  682. } finally {
  683. setTimeout(() => {
  684. chartLoading.value = false
  685. }, 300)
  686. }
  687. }
  688. // 处理标签切换
  689. const handleTabChange = () => {
  690. getChartData()
  691. console.log('标签切换调用图表')
  692. }
  693. const getAdminData = async function () {
  694. try {
  695. const result = await API({ url: '/admin/userinfo', data: {} })
  696. adminData.value = result
  697. console.log('用户信息', adminData.value)
  698. } catch (error) {
  699. console.log('请求失败', error)
  700. }
  701. }
  702. // 获取卡片数据
  703. const getCardData = async () => {
  704. try {
  705. const response = await API({ url: '/workbench/getCard', data: {} })
  706. workDataUpdateTime.value = response.updateTime
  707. // 周同比
  708. sumWow.value = response.sumWow.toFixed(2)
  709. // 日环比
  710. sumDaily.value = response.sumDaily.toFixed(2)
  711. if (response && response.data) {
  712. processData(response.data)
  713. } else if (Array.isArray(response?.marketCards)) {
  714. processData(response)
  715. } else {
  716. console.error('无效的API响应结构:', response)
  717. }
  718. } catch (error) {
  719. console.error('获取卡片数据失败:', error)
  720. }
  721. }
  722. const workDataUpdateTime = ref(null)
  723. // 标记当前激活的时间范围按钮
  724. const activeTimeRange = ref('')
  725. // 日期选择器变化时清除按钮激活状态
  726. const handleDatePickerChange = () => {
  727. activeTimeRange.value = ''
  728. }
  729. onMounted(async () => {
  730. await getAdminData()
  731. await getCardData()
  732. await getMarkets()
  733. getYear()
  734. window.addEventListener('resize', () => {
  735. chartInstance.resize()
  736. })
  737. })
  738. onUnmounted(() => {
  739. destroyChart()
  740. })
  741. </script>
  742. <style scoped>
  743. .top {
  744. height: 5.5%;
  745. width:100%;
  746. display: flex;
  747. margin-bottom: 0.2%;
  748. .text{
  749. margin-left:0.2%;
  750. width:50%;
  751. display: flex;
  752. align-items: center;
  753. font-size: 18px;
  754. }
  755. }
  756. .card {
  757. height: 28%;
  758. display: flex;
  759. justify-content: center;
  760. }
  761. .graph {
  762. width: 100%;
  763. display: flex;
  764. height: 64%;
  765. .condition {
  766. width: 100%;
  767. height: 1%;
  768. display: flex;
  769. align-items: center;
  770. }
  771. .graph-content {
  772. flex: 1;
  773. height: auto;
  774. display: flex;
  775. .left {
  776. width: 70%;
  777. height: auto;
  778. }
  779. .right {
  780. flex: 1;
  781. padding: 0.5% 2%;
  782. }
  783. }
  784. }
  785. .center-card {
  786. display: flex;
  787. justify-content: center;
  788. align-items: center;
  789. }
  790. .margin-bottom {
  791. margin-bottom: 0.5%;
  792. }
  793. .card-item {
  794. width: 25%;
  795. height: 98%;
  796. display: flex;
  797. flex-direction: column;
  798. justify-content: center;
  799. margin-right: 0.25%;
  800. }
  801. .card-title {
  802. font-weight: bold;
  803. margin-bottom: 10px;
  804. display: flex;
  805. justify-content: center;
  806. align-items: center;
  807. }
  808. .card-large {
  809. font-weight: bold;
  810. font-size: 16px;
  811. text-align: center;
  812. margin-bottom: 15px;
  813. }
  814. @keyframes spin {
  815. 0% {
  816. transform: rotate(0deg);
  817. }
  818. 100% {
  819. transform: rotate(360deg);
  820. }
  821. }
  822. </style>