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