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.

838 lines
24 KiB

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