Index2.vue 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. <script setup lang="ts">
  2. import { ref, reactive } from 'vue'
  3. import { set } from 'lodash-es'
  4. import { EChartsOption } from 'echarts'
  5. import { Echart } from '@/components/Echart'
  6. import { useI18n } from '@/hooks/web/useI18n'
  7. import { CountTo } from '@/components/CountTo'
  8. import type { AnalysisTotalTypes } from './types'
  9. import { useDesign } from '@/hooks/web/useDesign'
  10. import { ElRow, ElCol, ElCard, ElSkeleton } from 'element-plus'
  11. import { pieOptions, barOptions, lineOptions } from './echarts-data'
  12. const { t } = useI18n()
  13. const loading = ref(true)
  14. const { getPrefixCls } = useDesign()
  15. const prefixCls = getPrefixCls('panel')
  16. const pieOptionsData = reactive<EChartsOption>(pieOptions) as EChartsOption
  17. let totalState = reactive<AnalysisTotalTypes>({
  18. users: 0,
  19. messages: 0,
  20. moneys: 0,
  21. shoppings: 0
  22. })
  23. const getCount = async () => {
  24. const data = {
  25. users: 102400,
  26. messages: 81212,
  27. moneys: 9280,
  28. shoppings: 13600
  29. }
  30. totalState = Object.assign(totalState, data)
  31. }
  32. // 用户来源
  33. const getUserAccessSource = async () => {
  34. const data = [
  35. { value: 335, name: 'analysis.directAccess' },
  36. { value: 310, name: 'analysis.mailMarketing' },
  37. { value: 234, name: 'analysis.allianceAdvertising' },
  38. { value: 135, name: 'analysis.videoAdvertising' },
  39. { value: 1548, name: 'analysis.searchEngines' }
  40. ]
  41. set(
  42. pieOptionsData,
  43. 'legend.data',
  44. data.map((v) => t(v.name))
  45. )
  46. set(pieOptionsData, 'series.data', data)
  47. }
  48. const barOptionsData = reactive<EChartsOption>(barOptions) as EChartsOption
  49. // 周活跃量
  50. const getWeeklyUserActivity = async () => {
  51. const data = [
  52. { value: 13253, name: 'analysis.monday' },
  53. { value: 34235, name: 'analysis.tuesday' },
  54. { value: 26321, name: 'analysis.wednesday' },
  55. { value: 12340, name: 'analysis.thursday' },
  56. { value: 24643, name: 'analysis.friday' },
  57. { value: 1322, name: 'analysis.saturday' },
  58. { value: 1324, name: 'analysis.sunday' }
  59. ]
  60. set(
  61. barOptionsData,
  62. 'xAxis.data',
  63. data.map((v) => t(v.name))
  64. )
  65. set(barOptionsData, 'series', [
  66. {
  67. name: t('analysis.activeQuantity'),
  68. data: data.map((v) => v.value),
  69. type: 'bar'
  70. }
  71. ])
  72. }
  73. const lineOptionsData = reactive<EChartsOption>(lineOptions) as EChartsOption
  74. // 每月销售总额
  75. const getMonthlySales = async () => {
  76. const data = [
  77. { estimate: 100, actual: 120, name: 'analysis.january' },
  78. { estimate: 120, actual: 82, name: 'analysis.february' },
  79. { estimate: 161, actual: 91, name: 'analysis.march' },
  80. { estimate: 134, actual: 154, name: 'analysis.april' },
  81. { estimate: 105, actual: 162, name: 'analysis.may' },
  82. { estimate: 160, actual: 140, name: 'analysis.june' },
  83. { estimate: 165, actual: 145, name: 'analysis.july' },
  84. { estimate: 114, actual: 250, name: 'analysis.august' },
  85. { estimate: 163, actual: 134, name: 'analysis.september' },
  86. { estimate: 185, actual: 56, name: 'analysis.october' },
  87. { estimate: 118, actual: 99, name: 'analysis.november' },
  88. { estimate: 123, actual: 123, name: 'analysis.december' }
  89. ]
  90. set(
  91. lineOptionsData,
  92. 'xAxis.data',
  93. data.map((v) => t(v.name))
  94. )
  95. set(lineOptionsData, 'series', [
  96. {
  97. name: t('analysis.estimate'),
  98. smooth: true,
  99. type: 'line',
  100. data: data.map((v) => v.estimate),
  101. animationDuration: 2800,
  102. animationEasing: 'cubicInOut'
  103. },
  104. {
  105. name: t('analysis.actual'),
  106. smooth: true,
  107. type: 'line',
  108. itemStyle: {},
  109. data: data.map((v) => v.actual),
  110. animationDuration: 2800,
  111. animationEasing: 'quadraticOut'
  112. }
  113. ])
  114. }
  115. const getAllApi = async () => {
  116. await Promise.all([getCount(), getUserAccessSource(), getWeeklyUserActivity(), getMonthlySales()])
  117. loading.value = false
  118. }
  119. getAllApi()
  120. </script>
  121. <template>
  122. <el-row :gutter="20" justify="space-between" :class="prefixCls">
  123. <el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24">
  124. <el-card shadow="hover" class="mb-20px">
  125. <el-skeleton :loading="loading" animated :rows="2">
  126. <template #default>
  127. <div :class="`${prefixCls}__item flex justify-between`">
  128. <div>
  129. <div
  130. :class="`${prefixCls}__item--icon ${prefixCls}__item--peoples p-16px inline-block rounded-6px`"
  131. >
  132. <Icon icon="svg-icon:peoples" :size="40" />
  133. </div>
  134. </div>
  135. <div class="flex flex-col justify-between">
  136. <div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`">{{
  137. t('analysis.newUser')
  138. }}</div>
  139. <CountTo
  140. class="text-20px font-700 text-right"
  141. :start-val="0"
  142. :end-val="102400"
  143. :duration="2600"
  144. />
  145. </div>
  146. </div>
  147. </template>
  148. </el-skeleton>
  149. </el-card>
  150. </el-col>
  151. <el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24">
  152. <el-card shadow="hover" class="mb-20px">
  153. <el-skeleton :loading="loading" animated :rows="2">
  154. <template #default>
  155. <div :class="`${prefixCls}__item flex justify-between`">
  156. <div>
  157. <div
  158. :class="`${prefixCls}__item--icon ${prefixCls}__item--message p-16px inline-block rounded-6px`"
  159. >
  160. <Icon icon="svg-icon:message" :size="40" />
  161. </div>
  162. </div>
  163. <div class="flex flex-col justify-between">
  164. <div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`">{{
  165. t('analysis.unreadInformation')
  166. }}</div>
  167. <CountTo
  168. class="text-20px font-700 text-right"
  169. :start-val="0"
  170. :end-val="81212"
  171. :duration="2600"
  172. />
  173. </div>
  174. </div>
  175. </template>
  176. </el-skeleton>
  177. </el-card>
  178. </el-col>
  179. <el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24">
  180. <el-card shadow="hover" class="mb-20px">
  181. <el-skeleton :loading="loading" animated :rows="2">
  182. <template #default>
  183. <div :class="`${prefixCls}__item flex justify-between`">
  184. <div>
  185. <div
  186. :class="`${prefixCls}__item--icon ${prefixCls}__item--money p-16px inline-block rounded-6px`"
  187. >
  188. <Icon icon="svg-icon:money" :size="40" />
  189. </div>
  190. </div>
  191. <div class="flex flex-col justify-between">
  192. <div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`">{{
  193. t('analysis.transactionAmount')
  194. }}</div>
  195. <CountTo
  196. class="text-20px font-700 text-right"
  197. :start-val="0"
  198. :end-val="9280"
  199. :duration="2600"
  200. />
  201. </div>
  202. </div>
  203. </template>
  204. </el-skeleton>
  205. </el-card>
  206. </el-col>
  207. <el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24">
  208. <el-card shadow="hover" class="mb-20px">
  209. <el-skeleton :loading="loading" animated :rows="2">
  210. <template #default>
  211. <div :class="`${prefixCls}__item flex justify-between`">
  212. <div>
  213. <div
  214. :class="`${prefixCls}__item--icon ${prefixCls}__item--shopping p-16px inline-block rounded-6px`"
  215. >
  216. <Icon icon="svg-icon:shopping" :size="40" />
  217. </div>
  218. </div>
  219. <div class="flex flex-col justify-between">
  220. <div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`">{{
  221. t('analysis.totalShopping')
  222. }}</div>
  223. <CountTo
  224. class="text-20px font-700 text-right"
  225. :start-val="0"
  226. :end-val="13600"
  227. :duration="2600"
  228. />
  229. </div>
  230. </div>
  231. </template>
  232. </el-skeleton>
  233. </el-card>
  234. </el-col>
  235. </el-row>
  236. <el-row :gutter="20" justify="space-between">
  237. <el-col :xl="10" :lg="10" :md="24" :sm="24" :xs="24">
  238. <el-card shadow="hover" class="mb-20px">
  239. <el-skeleton :loading="loading" animated>
  240. <Echart :options="pieOptionsData" :height="300" />
  241. </el-skeleton>
  242. </el-card>
  243. </el-col>
  244. <el-col :xl="14" :lg="14" :md="24" :sm="24" :xs="24">
  245. <el-card shadow="hover" class="mb-20px">
  246. <el-skeleton :loading="loading" animated>
  247. <Echart :options="barOptionsData" :height="300" />
  248. </el-skeleton>
  249. </el-card>
  250. </el-col>
  251. <el-col :span="24">
  252. <el-card shadow="hover" class="mb-20px">
  253. <el-skeleton :loading="loading" animated :rows="4">
  254. <Echart :options="lineOptionsData" :height="350" />
  255. </el-skeleton>
  256. </el-card>
  257. </el-col>
  258. </el-row>
  259. </template>
  260. <style lang="less" scoped>
  261. @prefix-cls: ~'@{namespace}-panel';
  262. .@{prefix-cls} {
  263. &__item {
  264. &--peoples {
  265. color: #40c9c6;
  266. }
  267. &--message {
  268. color: #36a3f7;
  269. }
  270. &--money {
  271. color: #f4516c;
  272. }
  273. &--shopping {
  274. color: #34bfa3;
  275. }
  276. &:hover {
  277. :deep(.@{namespace}-icon) {
  278. color: #fff !important;
  279. }
  280. .@{prefix-cls}__item--icon {
  281. transition: all 0.38s ease-out;
  282. }
  283. .@{prefix-cls}__item--peoples {
  284. background: #40c9c6;
  285. }
  286. .@{prefix-cls}__item--message {
  287. background: #36a3f7;
  288. }
  289. .@{prefix-cls}__item--money {
  290. background: #f4516c;
  291. }
  292. .@{prefix-cls}__item--shopping {
  293. background: #34bfa3;
  294. }
  295. }
  296. }
  297. }
  298. </style>