浏览代码

feat: Add analysis demo

kailong321200875 3 年之前
父节点
当前提交
cd069340fc

+ 26 - 0
mock/analysis/index.ts

@@ -0,0 +1,26 @@
+import { config } from '@/config/axios/config'
+import { MockMethod } from 'vite-plugin-mock'
+
+const { result_code } = config
+
+const timeout = 1000
+
+export default [
+  // 分析页统计接口
+  {
+    url: '/analysis/total',
+    method: 'get',
+    timeout,
+    response: () => {
+      return {
+        code: result_code,
+        data: {
+          users: 102400,
+          messages: 81212,
+          moneys: 9280,
+          shoppings: 13600
+        }
+      }
+    }
+  }
+] as MockMethod[]

+ 7 - 0
src/api/dashboard/analysis/index.ts

@@ -0,0 +1,7 @@
+import { useAxios } from '@/hooks/web/useAxios'
+
+const { request } = useAxios()
+
+export const getCountApi = () => {
+  return request({ url: '/analysis/total', method: 'get' } as AxiosConfig)
+}

+ 6 - 0
src/api/dashboard/analysis/types.ts

@@ -0,0 +1,6 @@
+export type AnalysisTotalTypes = {
+  users: number
+  messages: number
+  moneys: number
+  shoppings: number
+}

+ 1 - 0
src/assets/svgs/message.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M0 20.967v59.59c0 11.59 8.537 20.966 19.075 20.966h28.613l1 26.477L76.8 101.523h32.125c10.538 0 19.075-9.377 19.075-20.966v-59.59C128 9.377 119.463 0 108.925 0h-89.85C8.538 0 0 9.377 0 20.967zm82.325 33.1c0-5.524 4.013-9.935 9.037-9.935 5.026 0 9.038 4.41 9.038 9.934 0 5.524-4.025 9.934-9.038 9.934-5.024 0-9.037-4.41-9.037-9.934zm-27.613 0c0-5.524 4.013-9.935 9.038-9.935s9.037 4.41 9.037 9.934c0 5.524-4.025 9.934-9.037 9.934-5.025 0-9.038-4.41-9.038-9.934zm-27.1 0c0-5.524 4.013-9.935 9.038-9.935s9.038 4.41 9.038 9.934c0 5.524-4.026 9.934-9.05 9.934-5.013 0-9.025-4.41-9.025-9.934z"/></svg>

+ 1 - 0
src/assets/svgs/money.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M54.122 127.892v-28.68H7.513V87.274h46.609v-12.4H7.513v-12.86h38.003L.099 0h22.6l32.556 45.07c3.617 5.144 6.44 9.611 8.487 13.385 1.788-3.05 4.89-7.779 9.301-14.186L103.93 0h24.01L82.385 62.013h38.34v12.862h-46.41v12.4h46.41v11.937h-46.41v28.68H54.123z"/></svg>

文件差异内容过多而无法显示
+ 0 - 0
src/assets/svgs/shopping.svg


+ 1 - 4
src/components/ConfigGlobal/src/ConfigGlobal.vue

@@ -8,9 +8,7 @@ import { useAppStore } from '@/store/modules/app'
 import { setCssVar } from '@/utils'
 import { useDesign } from '@/hooks/web/useDesign'
 
-const { getPrefixCls, variables } = useDesign()
-
-const prefixCls = getPrefixCls('config-global')
+const { variables } = useDesign()
 
 const appStore = useAppStore()
 
@@ -54,7 +52,6 @@ const currentLocale = computed(() => localeStore.currentLocale)
 
 <template>
   <ElConfigProvider
-    :clss="prefixCls"
     :namespace="variables.elNamespace"
     :locale="currentLocale.elLocale"
     :message="{ max: 1 }"

+ 5 - 0
src/components/ContextMenu/index.ts

@@ -1,3 +1,8 @@
 import ContextMenu from './src/ContextMenu.vue'
+import { ElDropdown } from 'element-plus'
+
+export interface ContextMenuExpose {
+  elDropdownMenuRef: ComponentRef<typeof ElDropdown>
+}
 
 export { ContextMenu }

+ 15 - 1
src/components/ContextMenu/src/ContextMenu.vue

@@ -1,6 +1,6 @@
 <script setup lang="ts">
 import { ElDropdown, ElDropdownMenu, ElDropdownItem } from 'element-plus'
-import { PropType } from 'vue'
+import { PropType, ref, unref } from 'vue'
 import { useI18n } from '@/hooks/web/useI18n'
 import { useDesign } from '@/hooks/web/useDesign'
 
@@ -10,6 +10,8 @@ const prefixCls = getPrefixCls('context-menu')
 
 const { t } = useI18n()
 
+const emit = defineEmits(['visibleChange'])
+
 defineProps({
   schema: {
     type: Array as PropType<contextMenuSchema[]>,
@@ -24,14 +26,26 @@ defineProps({
 const command = (item: contextMenuSchema) => {
   item.command && item.command(item)
 }
+
+const visibleChange = (visible: boolean) => {
+  emit('visibleChange', visible, unref(elDropdownMenuRef))
+}
+
+const elDropdownMenuRef = ref<ComponentRef<typeof ElDropdown>>()
+
+defineExpose({
+  elDropdownMenuRef
+})
 </script>
 
 <template>
   <ElDropdown
+    ref="elDropdownMenuRef"
     :class="prefixCls"
     :trigger="trigger"
     placement="bottom-start"
     @command="command"
+    @visible-change="visibleChange"
     popper-class="v-context-menu-popper"
   >
     <slot></slot>

+ 13 - 15
src/components/Echart/src/Echart.vue

@@ -9,7 +9,7 @@ import { useAppStore } from '@/store/modules/app'
 import { isString } from '@/utils/is'
 import { useDesign } from '@/hooks/web/useDesign'
 
-const { getPrefixCls } = useDesign()
+const { getPrefixCls, variables } = useDesign()
 
 const prefixCls = getPrefixCls('echart')
 
@@ -40,7 +40,7 @@ const options = computed(() => {
 
 const elRef = ref<ElRef>()
 
-const echartRef = ref<echarts.ECharts>()
+let echartRef: Nullable<echarts.ECharts> = null
 
 const contentEl = ref<Element>()
 
@@ -56,16 +56,16 @@ const styles = computed(() => {
 
 const initChart = () => {
   if (unref(elRef) && props.options) {
-    echartRef.value = echarts.init(unref(elRef) as HTMLElement, unref(options))
+    echartRef = echarts.init(unref(elRef) as HTMLElement)
+    echartRef?.setOption(unref(options))
   }
 }
 
 watch(
   () => options.value,
   (options) => {
-    const chart = unref(echartRef)
-    if (chart) {
-      chart?.setOption(options)
+    if (echartRef) {
+      echartRef?.setOption(options)
     }
   },
   {
@@ -74,13 +74,12 @@ watch(
 )
 
 const resizeHandler = debounce(() => {
-  const chart = unref(echartRef)
-  if (chart) {
-    chart.resize()
+  if (echartRef) {
+    echartRef.resize()
   }
 }, 100)
 
-const contentResizeHandler = (e: TransitionEvent) => {
+const contentResizeHandler = async (e: TransitionEvent) => {
   if (e.propertyName === 'width') {
     resizeHandler()
   }
@@ -91,7 +90,7 @@ onMounted(() => {
 
   window.addEventListener('resize', resizeHandler)
 
-  contentEl.value = document.getElementsByClassName('v-content')[0]
+  contentEl.value = document.getElementsByClassName(`${variables.namespace}-layout-content`)[0]
   unref(contentEl) &&
     (unref(contentEl) as Element).addEventListener('transitionend', contentResizeHandler)
 })
@@ -103,13 +102,12 @@ onBeforeUnmount(() => {
 })
 
 onActivated(() => {
-  const chart = unref(echartRef)
-  if (chart) {
-    chart.resize()
+  if (echartRef) {
+    echartRef.resize()
   }
 })
 </script>
 
 <template>
-  <div ref="elRef" :class="[$attrs.class, prefixCls]" :style="styles" />
+  <div ref="elRef" :class="[$attrs.class, prefixCls]" :style="styles"></div>
 </template>

+ 21 - 1
src/components/TagsView/src/TagsView.vue

@@ -6,8 +6,9 @@ import { usePermissionStore } from '@/store/modules/permission'
 import { useTagsViewStore } from '@/store/modules/tagsView'
 import { useI18n } from '@/hooks/web/useI18n'
 import { filterAffixTags } from './helper'
-import { ContextMenu } from '@/components/ContextMenu'
+import { ContextMenu, ContextMenuExpose } from '@/components/ContextMenu'
 import { useDesign } from '@/hooks/web/useDesign'
+import { useTemplateRefsList } from '@vueuse/core'
 
 const { getPrefixCls } = useDesign()
 
@@ -115,6 +116,23 @@ const isActive = (route: RouteLocationNormalizedLoaded): boolean => {
   return route.path === unref(currentRoute).path
 }
 
+const itemRefs = useTemplateRefsList<ComponentRef<typeof ContextMenu & ContextMenuExpose>>()
+
+const visibleChange = (
+  visible: boolean,
+  ref: ComponentRef<typeof ContextMenu & ContextMenuExpose>
+) => {
+  const uid = ref.$el['__vueParentComponent'].uid
+  if (visible) {
+    for (const v of unref(itemRefs)) {
+      const elDropdownMenuRef = v.elDropdownMenuRef
+      if (uid !== elDropdownMenuRef?.$el['__vueParentComponent'].uid) {
+        elDropdownMenuRef?.handleClose()
+      }
+    }
+  }
+}
+
 onMounted(() => {
   initTags()
   addTags()
@@ -141,6 +159,7 @@ watch(
       <ElScrollbar class="h-full">
         <div class="flex h-full">
           <ContextMenu
+            :ref="itemRefs.set"
             :schema="[
               {
                 icon: 'ant-design:sync-outlined',
@@ -207,6 +226,7 @@ watch(
                 'is-active': isActive(item)
               }
             ]"
+            @visible-change="visibleChange"
           >
             <router-link :to="{ ...item }" custom v-slot="{ navigate }">
               <div

+ 36 - 0
src/locales/en.ts

@@ -73,6 +73,42 @@ export default {
     dashboard: 'Dashboard',
     analysis: 'Analysis'
   },
+  analysis: {
+    newUser: 'New user',
+    unreadInformation: 'Unread information',
+    transactionAmount: 'Transaction amount',
+    totalShopping: 'Total Shopping',
+    monthlySales: 'Monthly sales',
+    userAccessSource: 'User access source',
+    january: 'January',
+    february: 'February',
+    march: 'March',
+    april: 'April',
+    may: 'May',
+    june: 'June',
+    july: 'July',
+    august: 'August',
+    september: 'September',
+    october: 'October',
+    november: 'November',
+    december: 'December',
+    estimate: 'Estimate',
+    actual: 'Actual',
+    directAccess: 'Airect access',
+    mailMarketing: 'Mail marketing',
+    allianceAdvertising: 'Alliance advertising',
+    videoAdvertising: 'Video advertising',
+    searchEngines: 'Search engines',
+    weeklyUserActivity: 'Weekly user activity',
+    activeQuantity: 'Active quantity',
+    monday: 'Monday',
+    tuesday: 'Tuesday',
+    wednesday: 'Wednesday',
+    thursday: 'Thursday',
+    friday: 'Friday',
+    saturday: 'Saturday',
+    sunday: 'Sunday'
+  },
   formDemo: {
     input: 'Input',
     inputNumber: 'InputNumber',

+ 36 - 0
src/locales/zh-CN.ts

@@ -73,6 +73,42 @@ export default {
     dashboard: '首页',
     analysis: '分析页'
   },
+  analysis: {
+    newUser: '新增用户',
+    unreadInformation: '未读消息',
+    transactionAmount: '成交金额',
+    totalShopping: '购物总量',
+    monthlySales: '每月销售额',
+    userAccessSource: '用户访问来源',
+    january: '一月',
+    february: '二月',
+    march: '三月',
+    april: '四月',
+    may: '五月',
+    june: '六月',
+    july: '七月',
+    august: '八月',
+    september: '九月',
+    october: '十月',
+    november: '十一月',
+    december: '十二月',
+    estimate: '预计',
+    actual: '实际',
+    directAccess: '直接访问',
+    mailMarketing: '邮件营销',
+    allianceAdvertising: '联盟广告',
+    videoAdvertising: '视频广告',
+    searchEngines: '搜索引擎',
+    weeklyUserActivity: '每周用户活跃量',
+    activeQuantity: '活跃量',
+    monday: '周一',
+    tuesday: '周二',
+    wednesday: '周三',
+    thursday: '周四',
+    friday: '周五',
+    saturday: '周六',
+    sunday: '周日'
+  },
   formDemo: {
     input: '输入框',
     inputNumber: '数字输入框',

+ 33 - 0
src/views/Dashboard/Analysis.vue

@@ -1,7 +1,40 @@
 <script setup lang="ts">
 import PanelGroup from './components/PanelGroup.vue'
+import { ElRow, ElCol, ElCard, ElSkeleton } from 'element-plus'
+import { Echart } from '@/components/Echart'
+import { pieOptions, barOptions, lineOptions } from './echarts-data'
+import { ref } from 'vue'
+
+const loading = ref(true)
+
+setTimeout(() => {
+  loading.value = false
+}, 1000)
 </script>
 
 <template>
   <PanelGroup />
+  <ElRow :gutter="20" justify="space-between">
+    <ElCol :xl="10" :lg="10" :md="24" :sm="24" :xs="24">
+      <ElCard shadow="hover" class="mb-20px">
+        <ElSkeleton :loading="loading" animated>
+          <Echart :options="pieOptions" :height="300" />
+        </ElSkeleton>
+      </ElCard>
+    </ElCol>
+    <ElCol :xl="14" :lg="14" :md="24" :sm="24" :xs="24">
+      <ElCard shadow="hover" class="mb-20px">
+        <ElSkeleton :loading="loading" animated>
+          <Echart :options="barOptions" :height="300" />
+        </ElSkeleton>
+      </ElCard>
+    </ElCol>
+    <ElCol :span="24">
+      <ElCard shadow="hover" class="mb-20px">
+        <ElSkeleton :loading="loading" animated :rows="4">
+          <Echart :options="lineOptions" :height="400" />
+        </ElSkeleton>
+      </ElCard>
+    </ElCol>
+  </ElRow>
 </template>

+ 176 - 23
src/views/Dashboard/components/PanelGroup.vue

@@ -1,25 +1,154 @@
 <script setup lang="ts">
-import { ElRow, ElCol, ElCard } from 'element-plus'
+import { ElRow, ElCol, ElCard, ElSkeleton } from 'element-plus'
 import { CountTo } from '@/components/CountTo'
+import { useDesign } from '@/hooks/web/useDesign'
+import { useI18n } from '@/hooks/web/useI18n'
+import { ref, reactive } from 'vue'
+import { getCountApi } from '@/api/dashboard/analysis'
+import type { AnalysisTotalTypes } from '@/api/dashboard/analysis/types'
+
+const { t } = useI18n()
+
+const { getPrefixCls } = useDesign()
+
+const prefixCls = getPrefixCls('panel')
+
+const loading = ref(true)
+
+let totalState = reactive<AnalysisTotalTypes>({
+  users: 0,
+  messages: 0,
+  moneys: 0,
+  shoppings: 0
+})
+
+const getCount = async () => {
+  const res = await getCountApi()
+    .catch(() => {})
+    .finally(() => {
+      loading.value = false
+    })
+  totalState = Object.assign(totalState, res?.data || {})
+}
+
+getCount()
 </script>
 
 <template>
-  <ElRow :gutter="20" class="v-panel">
-    <ElCol :xl="6" :lg="6" :md="6" :sm="6" :xs="1">
-      <ElCard shadow="hover">
-        <div class="v-panel-item flex justify-between">
-          <div>
-            <div
-              class="v-panel-item__icon v-panel-item__icon--peoples p-16px inline-block rounded-6px"
-            >
-              <Icon icon="svg-icon:peoples" :size="40" />
+  <ElRow :gutter="20" justify="space-between" :class="prefixCls">
+    <ElCol :xl="6" :lg="6" :md="12" :sm="12" :xs="24">
+      <ElCard shadow="hover" class="mb-20px">
+        <ElSkeleton :loading="loading" animated :rows="2">
+          <template #default>
+            <div :class="`${prefixCls}__item flex justify-between`">
+              <div>
+                <div
+                  :class="`${prefixCls}__item--icon ${prefixCls}__item--peoples p-16px inline-block rounded-6px`"
+                >
+                  <Icon icon="svg-icon:peoples" :size="40" />
+                </div>
+              </div>
+              <div class="flex flex-col justify-between">
+                <div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`">{{
+                  t('analysis.newUser')
+                }}</div>
+                <CountTo
+                  class="text-20px font-700 text-right"
+                  :start-val="0"
+                  :end-val="102400"
+                  :duration="2600"
+                />
+              </div>
             </div>
-          </div>
-          <div class="flex flex-col justify-between">
-            <div class="v-panel-item__text">新增用户</div>
-            <CountTo :start-val="0" :end-val="102400" :duration="2600" />
-          </div>
-        </div>
+          </template>
+        </ElSkeleton>
+      </ElCard>
+    </ElCol>
+
+    <ElCol :xl="6" :lg="6" :md="12" :sm="12" :xs="24">
+      <ElCard shadow="hover" class="mb-20px">
+        <ElSkeleton :loading="loading" animated :rows="2">
+          <template #default>
+            <div :class="`${prefixCls}__item flex justify-between`">
+              <div>
+                <div
+                  :class="`${prefixCls}__item--icon ${prefixCls}__item--message p-16px inline-block rounded-6px`"
+                >
+                  <Icon icon="svg-icon:message" :size="40" />
+                </div>
+              </div>
+              <div class="flex flex-col justify-between">
+                <div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`">{{
+                  t('analysis.unreadInformation')
+                }}</div>
+                <CountTo
+                  class="text-20px font-700 text-right"
+                  :start-val="0"
+                  :end-val="81212"
+                  :duration="2600"
+                />
+              </div>
+            </div>
+          </template>
+        </ElSkeleton>
+      </ElCard>
+    </ElCol>
+
+    <ElCol :xl="6" :lg="6" :md="12" :sm="12" :xs="24">
+      <ElCard shadow="hover" class="mb-20px">
+        <ElSkeleton :loading="loading" animated :rows="2">
+          <template #default>
+            <div :class="`${prefixCls}__item flex justify-between`">
+              <div>
+                <div
+                  :class="`${prefixCls}__item--icon ${prefixCls}__item--money p-16px inline-block rounded-6px`"
+                >
+                  <Icon icon="svg-icon:money" :size="40" />
+                </div>
+              </div>
+              <div class="flex flex-col justify-between">
+                <div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`">{{
+                  t('analysis.transactionAmount')
+                }}</div>
+                <CountTo
+                  class="text-20px font-700 text-right"
+                  :start-val="0"
+                  :end-val="9280"
+                  :duration="2600"
+                />
+              </div>
+            </div>
+          </template>
+        </ElSkeleton>
+      </ElCard>
+    </ElCol>
+
+    <ElCol :xl="6" :lg="6" :md="12" :sm="12" :xs="24">
+      <ElCard shadow="hover" class="mb-20px">
+        <ElSkeleton :loading="loading" animated :rows="2">
+          <template #default>
+            <div :class="`${prefixCls}__item flex justify-between`">
+              <div>
+                <div
+                  :class="`${prefixCls}__item--icon ${prefixCls}__item--shopping p-16px inline-block rounded-6px`"
+                >
+                  <Icon icon="svg-icon:shopping" :size="40" />
+                </div>
+              </div>
+              <div class="flex flex-col justify-between">
+                <div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`">{{
+                  t('analysis.totalShopping')
+                }}</div>
+                <CountTo
+                  class="text-20px font-700 text-right"
+                  :start-val="0"
+                  :end-val="13600"
+                  :duration="2600"
+                />
+              </div>
+            </div>
+          </template>
+        </ElSkeleton>
       </ElCard>
     </ElCol>
   </ElRow>
@@ -29,17 +158,41 @@ import { CountTo } from '@/components/CountTo'
 @prefix-cls: ~'@{namespace}-panel';
 
 .@{prefix-cls} {
-  &-item {
+  &__item {
+    &--peoples {
+      color: #40c9c6;
+    }
+
+    &--message {
+      color: #36a3f7;
+    }
+
+    &--money {
+      color: #f4516c;
+    }
+
+    &--shopping {
+      color: #34bfa3;
+    }
+
     &:hover {
-      :deep(.v-icon) {
+      :deep(.@{namespace}-icon) {
         color: #fff !important;
       }
-      .@{prefix-cls}-item__icon {
+      .@{prefix-cls}__item--icon {
         transition: all 0.38s ease-out;
-
-        &--peoples {
-          background: #40c9c6;
-        }
+      }
+      .@{prefix-cls}__item--peoples {
+        background: #40c9c6;
+      }
+      .@{prefix-cls}__item--message {
+        background: #36a3f7;
+      }
+      .@{prefix-cls}__item--money {
+        background: #f4516c;
+      }
+      .@{prefix-cls}__item--shopping {
+        background: #34bfa3;
       }
     }
   }

+ 153 - 0
src/views/Dashboard/echarts-data.ts

@@ -0,0 +1,153 @@
+import { EChartsOption } from 'echarts'
+import { useI18n } from '@/hooks/web/useI18n'
+
+const { t } = useI18n()
+
+export const lineOptions: EChartsOption = {
+  title: {
+    text: t('analysis.monthlySales'),
+    left: 'center'
+  },
+  xAxis: {
+    data: [
+      t('analysis.january'),
+      t('analysis.february'),
+      t('analysis.march'),
+      t('analysis.april'),
+      t('analysis.may'),
+      t('analysis.june'),
+      t('analysis.july'),
+      t('analysis.august'),
+      t('analysis.september'),
+      t('analysis.october'),
+      t('analysis.november'),
+      t('analysis.december')
+    ],
+    boundaryGap: false,
+    axisTick: {
+      show: false
+    }
+  },
+  grid: {
+    left: 20,
+    right: 20,
+    bottom: 20,
+    top: 80,
+    containLabel: true
+  },
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'cross'
+    },
+    padding: [5, 10]
+  },
+  yAxis: {
+    axisTick: {
+      show: false
+    }
+  },
+  legend: {
+    data: [t('analysis.estimate'), t('analysis.actual')],
+    top: 50
+  },
+  series: [
+    {
+      name: t('analysis.estimate'),
+      smooth: true,
+      type: 'line',
+      data: [100, 120, 161, 134, 105, 160, 165, 114, 163, 185, 118, 123],
+      animationDuration: 2800,
+      animationEasing: 'cubicInOut'
+    },
+    {
+      name: t('analysis.actual'),
+      smooth: true,
+      type: 'line',
+      itemStyle: {},
+      data: [120, 82, 91, 154, 162, 140, 145, 250, 134, 56, 99, 123],
+      animationDuration: 2800,
+      animationEasing: 'quadraticOut'
+    }
+  ]
+}
+
+export const pieOptions: EChartsOption = {
+  title: {
+    text: t('analysis.userAccessSource'),
+    left: 'center'
+  },
+  tooltip: {
+    trigger: 'item',
+    formatter: '{a} <br/>{b} : {c} ({d}%)'
+  },
+  legend: {
+    orient: 'vertical',
+    left: 'left',
+    data: [
+      t('analysis.directAccess'),
+      t('analysis.mailMarketing'),
+      t('analysis.allianceAdvertising'),
+      t('analysis.videoAdvertising'),
+      t('analysis.searchEngines')
+    ]
+  },
+  series: [
+    {
+      name: t('analysis.userAccessSource'),
+      type: 'pie',
+      radius: '55%',
+      center: ['50%', '60%'],
+      data: [
+        { value: 335, name: t('analysis.directAccess') },
+        { value: 310, name: t('analysis.mailMarketing') },
+        { value: 234, name: t('analysis.allianceAdvertising') },
+        { value: 135, name: t('analysis.videoAdvertising') },
+        { value: 1548, name: t('analysis.searchEngines') }
+      ]
+    }
+  ]
+}
+
+export const barOptions: EChartsOption = {
+  title: {
+    text: t('analysis.weeklyUserActivity'),
+    left: 'center'
+  },
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'shadow'
+    }
+  },
+  grid: {
+    left: 50,
+    right: 20,
+    bottom: 20
+  },
+  xAxis: {
+    type: 'category',
+    data: [
+      t('analysis.monday'),
+      t('analysis.tuesday'),
+      t('analysis.wednesday'),
+      t('analysis.thursday'),
+      t('analysis.friday'),
+      t('analysis.saturday'),
+      t('analysis.sunday')
+    ],
+    axisTick: {
+      alignWithLabel: true
+    }
+  },
+  yAxis: {
+    type: 'value'
+  },
+  series: [
+    {
+      name: t('analysis.activeQuantity'),
+      data: [13253, 34235, 26321, 12340, 24643, 1322, 1324],
+      type: 'bar'
+    }
+  ]
+}

+ 10 - 2
src/views/Login/Login.vue

@@ -5,6 +5,11 @@ import { LocaleDropdown } from '@/components/LocaleDropdown'
 import { useI18n } from '@/hooks/web/useI18n'
 import { underlineToHump } from '@/utils'
 import { useAppStore } from '@/store/modules/app'
+import { useDesign } from '@/hooks/web/useDesign'
+
+const { getPrefixCls } = useDesign()
+
+const prefixCls = getPrefixCls('login')
 
 const appStore = useAppStore()
 
@@ -13,10 +18,13 @@ const { t } = useI18n()
 
 <template>
   <div
-    class="v-login h-[100%] relative overflow-hidden <xl:bg-v-dark <sm:px-10px <xl:px-10px <md:px-10px"
+    :class="prefixCls"
+    class="h-[100%] relative overflow-hidden <xl:bg-v-dark <sm:px-10px <xl:px-10px <md:px-10px"
   >
     <div class="relative h-full flex mx-auto">
-      <div class="v-login__left flex-1 bg-gray-500 bg-opacity-20 relative p-30px <xl:hidden">
+      <div
+        :class="`${prefixCls}__left flex-1 bg-gray-500 bg-opacity-20 relative p-30px <xl:hidden`"
+      >
         <div class="flex items-center relative text-white">
           <img src="@/assets/imgs/logo.png" alt="" class="w-48px h-48px mr-10px" />
           <span class="text-20px font-bold">{{ underlineToHump(appStore.getTitle) }}</span>

+ 3 - 1
vite.config.ts

@@ -130,7 +130,9 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
         '@iconify/iconify',
         '@vueuse/core',
         'axios',
-        'qs'
+        'qs',
+        'echarts',
+        'echarts-wordcloud'
       ]
     }
   }

部分文件因为文件数量过多而无法显示