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.

770 lines
22 KiB

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