Browse Source

!225 refactor: vue3 index
Merge pull request !225 from xingyu/master

芋道源码 2 years ago
parent
commit
9b267746ab

+ 32 - 35
README.md

@@ -153,29 +153,29 @@ ps:核心功能已经实现,正在对接微信小程序中...
 
 ### 后端
 
-| 框架                                                                                          | 说明               | 版本       | 学习指南                                                           |
-|---------------------------------------------------------------------------------------------|------------------|----------|----------------------------------------------------------------|
-| [Spring Boot](https://spring.io/projects/spring-boot)                                       | 应用开发框架           | 2.6.8   | [文档](https://github.com/YunaiV/SpringBoot-Labs)                |
-| [MySQL](https://www.mysql.com/cn/)                                                          | 数据库服务器           | 5.7      |                                                                |
-| [Druid](https://github.com/alibaba/druid)                                                   | JDBC 连接池、监控组件    | 1.2.8    | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
-| [MyBatis Plus](https://mp.baomidou.com/)                                                    | MyBatis 增强工具包    | 3.5.2    | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao)         |
-| [Dynamic Datasource](https://dynamic-datasource.com/)                                       | 动态数据源            | 3.5.0    | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
-| [Redis](https://redis.io/)                                                                  | key-value 数据库    | 5.0      |                                                                |
-| [Redisson](https://github.com/redisson/redisson)                                            | Redis 客户端        | 3.17.3   | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao)           |
-| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架           | 5.3.20   | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao)               |
-| [Spring Security](https://github.com/spring-projects/spring-security)                       | Spring 安全框架      | 5.6.5    | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |
-| [Hibernate Validator](https://github.com/hibernate/hibernate-validator)                     | 参数校验组件           | 6.2.3    | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao)      |
-| [Flowable](https://github.com/flowable/flowable-engine)                                            | 工作流引擎            | 6.7.0 | [文档](https://doc.iocoder.cn/bpm/)                                                     |
-| [Quartz](https://github.com/quartz-scheduler)                                               | 任务调度组件           | 2.3.2    | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao)             |
-| [Knife4j](https://gitee.com/xiaoym/knife4j)                                                 | Swagger 增强 UI 实现 | 3.0.3    | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao)         |
-| [Resilience4j](https://github.com/resilience4j/resilience4j)                                | 服务保障组件           | 1.7.1    | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao)    |
+| 框架                                                                                         | 说明                   | 版本      | 学习指南                                                           |
+|---------------------------------------------------------------------------------------------|-----------------------|-----------|----------------------------------------------------------------|
+| [Spring Boot](https://spring.io/projects/spring-boot)                                       | 应用开发框架             | 2.6.9    | [文档](https://github.com/YunaiV/SpringBoot-Labs)                |
+| [MySQL](https://www.mysql.com/cn/)                                                          | 数据库服务器             | 5.7      |                                                                |
+| [Druid](https://github.com/alibaba/druid)                                                   | JDBC 连接池、监控组件     | 1.2.8    | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
+| [MyBatis Plus](https://mp.baomidou.com/)                                                    | MyBatis 增强工具包       | 3.5.2    | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao)         |
+| [Dynamic Datasource](https://dynamic-datasource.com/)                                       | 动态数据源               | 3.5.0    | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
+| [Redis](https://redis.io/)                                                                  | key-value 数据库        | 5.0      |                                                                |
+| [Redisson](https://github.com/redisson/redisson)                                            | Redis 客户端            | 3.17.4   | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao)           |
+| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架               | 5.3.20    | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao)               |
+| [Spring Security](https://github.com/spring-projects/spring-security)                       | Spring 安全框架         | 5.6.5    | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |
+| [Hibernate Validator](https://github.com/hibernate/hibernate-validator)                     | 参数校验组件             | 6.2.3    | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao)      |
+| [Flowable](https://github.com/flowable/flowable-engine)                                     | 工作流引擎               | 6.7.0    | [文档](https://doc.iocoder.cn/bpm/)                                                     |
+| [Quartz](https://github.com/quartz-scheduler)                                               | 任务调度组件             | 2.3.2    | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao)             |
+| [Knife4j](https://gitee.com/xiaoym/knife4j)                                                 | Swagger 增强 UI 实现    | 3.0.3    | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao)         |
+| [Resilience4j](https://github.com/resilience4j/resilience4j)                                | 服务保障组件             | 1.7.1    | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao)    |
 | [SkyWalking](https://skywalking.apache.org/)                                                | 分布式应用追踪系统        | 8.5.0    | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao)      |
-| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin)                       | Spring Boot 监控平台 | 2.6.7    | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao)           |
-| [Jackson](https://github.com/FasterXML/jackson)                                             | JSON 工具库         | 2.13.3   |                                                                |
-| [MapStruct](https://mapstruct.org/)                                                         | Java Bean 转换     | 1.4.1    | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao)       |
-| [Lombok](https://projectlombok.org/)                                                        | 消除冗长的 Java 代码    | 1.16.14  | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao)          |
-| [JUnit](https://junit.org/junit5/)                                                          | Java 单元测试框架      | 5.8.2    | -                                                              |
-| [Mockito](https://github.com/mockito/mockito)                                               | Java Mock 框架     | 4.0.0    | -                                                              |
+| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin)                       | Spring Boot 监控平台    | 2.6.7    | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao)           |
+| [Jackson](https://github.com/FasterXML/jackson)                                             | JSON 工具库             | 2.13.3   |                                                                |
+| [MapStruct](https://mapstruct.org/)                                                         | Java Bean 转换         | 1.4.1    | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao)       |
+| [Lombok](https://projectlombok.org/)                                                        | 消除冗长的 Java 代码     | 1.16.14  | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao)          |
+| [JUnit](https://junit.org/junit5/)                                                          | Java 单元测试框架        | 5.8.2    | -                                                              |
+| [Mockito](https://github.com/mockito/mockito)                                               | Java Mock 框架         | 4.0.0    | -                                                              |
 
 ### vue2 前端
 
@@ -186,19 +186,16 @@ ps:核心功能已经实现,正在对接微信小程序中...
 
 ### vue3 前端
 
-| 框架                                                                           | 说明            | 版本     |
-|------------------------------------------------------------------------------|---------------|--------|
-| [Vue](https://staging-cn.vuejs.org/) | vue 框架 | 3.2.37 |
-| [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 3.0.1 |
-| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.2.9 |
-| [TypeScript](https://www.typescriptlang.org/docs/) | JavaScript 的超集 | 4.7.4 |
-| [pinia](https://pinia.vuejs.org/) | Vue 存储库 替代 vuex5 | 2.0.16 |
-| [vueuse](https://vueuse.org//) | 常用工具集 | 8.9.4 |
-| [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.1.10 |
-| [vue-router](https://router.vuejs.org/) | vue 路由 | 4.1.2 |
-| [windicss](https://cn.windicss.org/) | 下一代工具优先的 CSS 框架 | 3.5.6 |
-| [iconify](https://icon-sets.iconify.design/) | 在线图标库 | 2.2.1 |
-| [wangeditor](https://www.wangeditor.com/) | 富文本编辑器 | 5.1.11 |
+| 框架                                                                  | 说明                 | 版本     |
+|----------------------------------------------------------------------|---------------------|--------|
+| [Vue](https://staging-cn.vuejs.org/)                                 | vue 框架             | 3.2.37 |
+| [Vite](https://cn.vitejs.dev//)                                      | 开发与构建工具         | 3.0.2  |
+| [Element Plus](https://element-plus.org/zh-CN/)                      | Element Plus        | 2.2.9  |
+| [TypeScript](https://www.typescriptlang.org/docs/)                   | JavaScript 的超集    | 4.7.4  |
+| [pinia](https://pinia.vuejs.org/)                                    | Vue 存储库 替代 vuex5 | 2.0.16 |
+| [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化               | 9.1.10 |
+| [windicss](https://cn.windicss.org/)                                 | 下一代工具优先的 CSS 框架| 3.5.6  |
+| [iconify](https://icon-sets.iconify.design/)                         | 在线图标库             | 2.2.1  |
 
 ## 🐷 演示图
 

+ 1 - 1
yudao-ui-admin-vue3/package.json

@@ -6,7 +6,7 @@
   "private": false,
   "scripts": {
     "i": "pnpm install",
-    "dev": "vite --mode base",
+    "dev": "vite --mode base --open",
     "ts:check": "vue-tsc --noEmit",
     "build:pro": "vite build --mode pro",
     "build:dev": "vite build --mode dev",

+ 3 - 2
yudao-ui-admin-vue3/src/locales/en.ts

@@ -171,15 +171,16 @@ export default {
     sunday: 'Sunday'
   },
   workplace: {
-    goodMorning: 'Good morning',
+    welcome: 'Hello',
     happyDay: 'Wish you happy every day!',
     toady: `It's sunny today`,
+    notice: 'Announcement',
     project: 'Project',
     access: 'Project access',
     toDo: 'To do',
     introduction: 'A serious introduction',
     more: 'More',
-    shortcutOperation: 'Shortcut operation',
+    shortcutOperation: 'Quick entry',
     operation: 'Operation',
     index: 'Index',
     personal: 'Personal',

+ 3 - 2
yudao-ui-admin-vue3/src/locales/zh-CN.ts

@@ -171,15 +171,16 @@ export default {
     sunday: '周日'
   },
   workplace: {
-    goodMorning: '早安',
+    welcome: '你好',
     happyDay: '祝你开心每一天!',
     toady: '今日晴',
+    notice: '通知公告',
     project: '项目数',
     access: '项目访问',
     toDo: '待办',
     introduction: '一个正经的简介',
     more: '更多',
-    shortcutOperation: '快捷操作',
+    shortcutOperation: '快捷入口',
     operation: '操作',
     index: '指数',
     personal: '个人',

+ 329 - 170
yudao-ui-admin-vue3/src/views/Home/Index.vue

@@ -1,38 +1,199 @@
 <script setup lang="ts">
-import { ref, reactive } from 'vue'
-import { set } from 'lodash-es'
-import { EChartsOption } from 'echarts'
-import { Echart } from '@/components/Echart'
+import { ElRow, ElCol, ElSkeleton, ElCard, ElDivider, ElLink } from 'element-plus'
 import { useI18n } from '@/hooks/web/useI18n'
+import { ref, reactive } from 'vue'
 import { CountTo } from '@/components/CountTo'
-import type { AnalysisTotalTypes } from './types'
-import { useDesign } from '@/hooks/web/useDesign'
-import { ElRow, ElCol, ElCard, ElSkeleton } from 'element-plus'
+import { formatTime } from '@/utils'
+import { Echart } from '@/components/Echart'
+import { EChartsOption } from 'echarts'
+import { radarOption } from './echarts-data'
+import { Highlight } from '@/components/Highlight'
+import type { WorkplaceTotal, Project, Notice, Shortcut } from './types'
+import { set } from 'lodash-es'
+import { useCache } from '@/hooks/web/useCache'
 import { pieOptions, barOptions, lineOptions } from './echarts-data'
 
 const { t } = useI18n()
+const { wsCache } = useCache()
 const loading = ref(true)
-const { getPrefixCls } = useDesign()
-const prefixCls = getPrefixCls('panel')
+const avatar = wsCache.get('user').user.avatar
+const username = wsCache.get('user').user.nickname
 const pieOptionsData = reactive<EChartsOption>(pieOptions) as EChartsOption
-
-let totalState = reactive<AnalysisTotalTypes>({
-  users: 0,
-  messages: 0,
-  moneys: 0,
-  shoppings: 0
+// 获取统计数
+let totalSate = reactive<WorkplaceTotal>({
+  project: 0,
+  access: 0,
+  todo: 0
 })
 
 const getCount = async () => {
   const data = {
-    users: 102400,
-    messages: 81212,
-    moneys: 9280,
-    shoppings: 13600
+    project: 40,
+    access: 2340,
+    todo: 10
   }
-  totalState = Object.assign(totalState, data)
+  totalSate = Object.assign(totalSate, data)
+}
+
+// 获取项目数
+let projects = reactive<Project[]>([])
+const getProject = async () => {
+  const data = [
+    {
+      name: 'Github',
+      icon: 'akar-icons:github-fill',
+      message: 'workplace.introduction',
+      personal: 'Archer',
+      time: new Date()
+    },
+    {
+      name: 'Vue',
+      icon: 'logos:vue',
+      message: 'workplace.introduction',
+      personal: 'Archer',
+      time: new Date()
+    },
+    {
+      name: 'Angular',
+      icon: 'logos:angular-icon',
+      message: 'workplace.introduction',
+      personal: 'Archer',
+      time: new Date()
+    },
+    {
+      name: 'React',
+      icon: 'logos:react',
+      message: 'workplace.introduction',
+      personal: 'Archer',
+      time: new Date()
+    },
+    {
+      name: 'Webpack',
+      icon: 'logos:webpack',
+      message: 'workplace.introduction',
+      personal: 'Archer',
+      time: new Date()
+    },
+    {
+      name: 'Vite',
+      icon: 'vscode-icons:file-type-vite',
+      message: 'workplace.introduction',
+      personal: 'Archer',
+      time: new Date()
+    }
+  ]
+  projects = Object.assign(projects, data)
 }
 
+// 获取通知公告
+let notice = reactive<Notice[]>([])
+const getNotice = async () => {
+  const data = [
+    {
+      title: '系统升级版本',
+      type: '通知',
+      keys: ['通知', '升级'],
+      date: new Date()
+    },
+    {
+      title: '系统凌晨维护',
+      type: '公告',
+      keys: ['公告', '维护'],
+      date: new Date()
+    },
+    {
+      title: '系统升级版本',
+      type: '通知',
+      keys: ['通知', '升级'],
+      date: new Date()
+    },
+    {
+      title: '系统凌晨维护',
+      type: '公告',
+      keys: ['公告', '维护'],
+      date: new Date()
+    }
+  ]
+  notice = Object.assign(notice, data)
+}
+
+// 获取快捷入口
+let shortcut = reactive<Shortcut[]>([])
+
+const getShortcut = async () => {
+  const data = [
+    {
+      name: 'Github',
+      icon: 'akar-icons:github-fill',
+      url: 'github.io'
+    },
+    {
+      name: 'Vue',
+      icon: 'logos:vue',
+      url: 'vuejs.org'
+    },
+    {
+      name: 'Vite',
+      icon: 'vscode-icons:file-type-vite',
+      url: 'https://vitejs.dev/'
+    },
+    {
+      name: 'Angular',
+      icon: 'logos:angular-icon',
+      url: 'github.io'
+    },
+    {
+      name: 'React',
+      icon: 'logos:react',
+      url: 'github.io'
+    },
+    {
+      name: 'Webpack',
+      icon: 'logos:webpack',
+      url: 'github.io'
+    }
+  ]
+  shortcut = Object.assign(shortcut, data)
+}
+
+// 获取指数
+let radarOptionData = reactive<EChartsOption>(radarOption) as EChartsOption
+
+const getRadar = async () => {
+  const data = [
+    { name: 'workplace.quote', max: 65, personal: 42, team: 50 },
+    { name: 'workplace.contribution', max: 160, personal: 30, team: 140 },
+    { name: 'workplace.hot', max: 300, personal: 20, team: 28 },
+    { name: 'workplace.yield', max: 130, personal: 35, team: 35 },
+    { name: 'workplace.follow', max: 100, personal: 80, team: 90 }
+  ]
+  set(
+    radarOptionData,
+    'radar.indicator',
+    data.map((v) => {
+      return {
+        name: t(v.name),
+        max: v.max
+      }
+    })
+  )
+  set(radarOptionData, 'series', [
+    {
+      name: '指数',
+      type: 'radar',
+      data: [
+        {
+          value: data.map((v) => v.personal),
+          name: t('workplace.personal')
+        },
+        {
+          value: data.map((v) => v.team),
+          name: t('workplace.team')
+        }
+      ]
+    }
+  ])
+}
 // 用户来源
 const getUserAccessSource = async () => {
   const data = [
@@ -121,7 +282,16 @@ const getMonthlySales = async () => {
 }
 
 const getAllApi = async () => {
-  await Promise.all([getCount(), getUserAccessSource(), getWeeklyUserActivity(), getMonthlySales()])
+  await Promise.all([
+    getCount(),
+    getProject(),
+    getNotice(),
+    getShortcut(),
+    getRadar(),
+    getUserAccessSource(),
+    getWeeklyUserActivity(),
+    getMonthlySales()
+  ])
   loading.value = false
 }
 
@@ -129,188 +299,177 @@ getAllApi()
 </script>
 
 <template>
-  <el-row :gutter="20" justify="space-between" :class="prefixCls">
-    <el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24">
-      <el-card shadow="hover" class="mb-20px">
-        <el-skeleton :loading="loading" animated :rows="2">
-          <template #default>
-            <div :class="`${prefixCls}__item flex justify-between`">
+  <div>
+    <el-card shadow="never">
+      <el-skeleton :loading="loading" animated>
+        <el-row :gutter="20" justify="space-between">
+          <el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24">
+            <div class="flex items-center">
+              <img :src="avatar" alt="" class="w-70px h-70px rounded-[50%] mr-20px" />
               <div>
-                <div
-                  :class="`${prefixCls}__item--icon ${prefixCls}__item--peoples p-16px inline-block rounded-6px`"
-                >
-                  <Icon icon="svg-icon:peoples" :size="40" />
+                <div class="text-20px text-700">
+                  {{ t('workplace.welcome') }} {{ username }} {{ t('workplace.happyDay') }}
+                </div>
+                <div class="mt-10px text-14px text-gray-500">
+                  {{ t('workplace.toady') }},20℃ - 32℃!
                 </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>
+            </div>
+          </el-col>
+          <el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24">
+            <div class="flex h-70px items-center justify-end <sm:mt-10px">
+              <div class="px-8px text-right">
+                <div class="text-14px text-gray-400 mb-20px">{{ t('workplace.project') }}</div>
                 <CountTo
-                  class="text-20px font-700 text-right"
+                  class="text-20px"
                   :start-val="0"
-                  :end-val="102400"
+                  :end-val="totalSate.project"
                   :duration="2600"
                 />
               </div>
-            </div>
-          </template>
-        </el-skeleton>
-      </el-card>
-    </el-col>
-
-    <el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24">
-      <el-card shadow="hover" class="mb-20px">
-        <el-skeleton :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>
+              <el-divider direction="vertical" />
+              <div class="px-8px text-right">
+                <div class="text-14px text-gray-400 mb-20px">{{ t('workplace.toDo') }}</div>
                 <CountTo
-                  class="text-20px font-700 text-right"
+                  class="text-20px"
                   :start-val="0"
-                  :end-val="81212"
+                  :end-val="totalSate.todo"
                   :duration="2600"
                 />
               </div>
-            </div>
-          </template>
-        </el-skeleton>
-      </el-card>
-    </el-col>
-
-    <el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24">
-      <el-card shadow="hover" class="mb-20px">
-        <el-skeleton :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>
+              <el-divider direction="vertical" border-style="dashed" />
+              <div class="px-8px text-right">
+                <div class="text-14px text-gray-400 mb-20px">{{ t('workplace.access') }}</div>
                 <CountTo
-                  class="text-20px font-700 text-right"
+                  class="text-20px"
                   :start-val="0"
-                  :end-val="9280"
+                  :end-val="totalSate.access"
                   :duration="2600"
                 />
               </div>
             </div>
-          </template>
+          </el-col>
+        </el-row>
+      </el-skeleton>
+    </el-card>
+  </div>
+
+  <el-row class="mt-10px" :gutter="20" justify="space-between">
+    <el-col :xl="16" :lg="16" :md="24" :sm="24" :xs="24" class="mb-20px">
+      <el-card shadow="never">
+        <template #header>
+          <div class="flex justify-between">
+            <span>{{ t('workplace.project') }}</span>
+            <el-link type="primary" :underline="false">{{ t('workplace.more') }}</el-link>
+          </div>
+        </template>
+        <el-skeleton :loading="loading" animated>
+          <el-row>
+            <el-col
+              v-for="(item, index) in projects"
+              :key="`card-${index}`"
+              :xl="8"
+              :lg="8"
+              :md="12"
+              :sm="24"
+              :xs="24"
+            >
+              <el-card shadow="hover">
+                <div class="flex items-center">
+                  <Icon :icon="item.icon" :size="25" class="mr-10px" />
+                  <span class="text-16px">{{ item.name }}</span>
+                </div>
+                <div class="mt-15px text-14px text-gray-400">{{ t(item.message) }}</div>
+                <div class="mt-20px text-12px text-gray-400 flex justify-between">
+                  <span>{{ item.personal }}</span>
+                  <span>{{ formatTime(item.time, 'yyyy-MM-dd') }}</span>
+                </div>
+              </el-card>
+            </el-col>
+          </el-row>
         </el-skeleton>
       </el-card>
-    </el-col>
 
-    <el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24">
-      <el-card shadow="hover" class="mb-20px">
-        <el-skeleton :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>
+      <el-card shadow="never" class="mt-10px">
+        <el-skeleton :loading="loading" animated>
+          <el-row :gutter="20" justify="space-between">
+            <el-col :xl="10" :lg="10" :md="24" :sm="24" :xs="24">
+              <el-card shadow="hover" class="mb-20px">
+                <el-skeleton :loading="loading" animated>
+                  <Echart :options="pieOptionsData" :height="300" />
+                </el-skeleton>
+              </el-card>
+            </el-col>
+            <el-col :xl="14" :lg="14" :md="24" :sm="24" :xs="24">
+              <el-card shadow="hover" class="mb-20px">
+                <el-skeleton :loading="loading" animated>
+                  <Echart :options="barOptionsData" :height="300" />
+                </el-skeleton>
+              </el-card>
+            </el-col>
+            <el-col :span="24">
+              <el-card shadow="hover" class="mb-20px">
+                <el-skeleton :loading="loading" animated :rows="4">
+                  <Echart :options="lineOptionsData" :height="350" />
+                </el-skeleton>
+              </el-card>
+            </el-col>
+          </el-row>
         </el-skeleton>
       </el-card>
     </el-col>
-  </el-row>
-  <el-row :gutter="20" justify="space-between">
-    <el-col :xl="10" :lg="10" :md="24" :sm="24" :xs="24">
-      <el-card shadow="hover" class="mb-20px">
+    <el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24" class="mb-20px">
+      <el-card shadow="never">
+        <template #header>
+          <span>{{ t('workplace.shortcutOperation') }}</span>
+        </template>
         <el-skeleton :loading="loading" animated>
-          <Echart :options="pieOptionsData" :height="300" />
+          <el-row>
+            <el-col v-for="item in shortcut" :key="`team-${item.name}`" :span="8" class="mb-20px">
+              <div class="flex items-center">
+                <Icon :icon="item.icon" class="mr-10px" />
+                <el-link type="default" :underline="false" :href="item.url">
+                  {{ item.name }}
+                </el-link>
+              </div>
+            </el-col>
+          </el-row>
         </el-skeleton>
       </el-card>
-    </el-col>
-    <el-col :xl="14" :lg="14" :md="24" :sm="24" :xs="24">
-      <el-card shadow="hover" class="mb-20px">
+      <el-card shadow="never" class="mt-10px">
+        <template #header>
+          <div class="flex justify-between">
+            <span>{{ t('workplace.notice') }}</span>
+            <el-link type="primary" :underline="false">{{ t('workplace.more') }}</el-link>
+          </div>
+        </template>
         <el-skeleton :loading="loading" animated>
-          <Echart :options="barOptionsData" :height="300" />
+          <div v-for="(item, index) in notice" :key="`dynamics-${index}`">
+            <div class="flex items-center">
+              <img :src="avatar" alt="" class="w-35px h-35px rounded-[50%] mr-20px" />
+              <div>
+                <div class="text-14px">
+                  <Highlight :keys="item.keys.map((v) => t(v))">
+                    {{ item.type }} : {{ item.title }}
+                  </Highlight>
+                </div>
+                <div class="mt-15px text-12px text-gray-400">
+                  {{ formatTime(item.date, 'yyyy-MM-dd') }}
+                </div>
+              </div>
+            </div>
+            <el-divider />
+          </div>
         </el-skeleton>
       </el-card>
-    </el-col>
-    <el-col :span="24">
-      <el-card shadow="hover" class="mb-20px">
-        <el-skeleton :loading="loading" animated :rows="4">
-          <Echart :options="lineOptionsData" :height="350" />
+      <el-card shadow="never" class="mt-10px">
+        <template #header>
+          <span>{{ t('workplace.index') }}</span>
+        </template>
+        <el-skeleton :loading="loading" animated>
+          <Echart :options="radarOptionData" :height="400" />
         </el-skeleton>
       </el-card>
     </el-col>
   </el-row>
 </template>
-<style lang="less" scoped>
-@prefix-cls: ~'@{namespace}-panel';
-
-.@{prefix-cls} {
-  &__item {
-    &--peoples {
-      color: #40c9c6;
-    }
-
-    &--message {
-      color: #36a3f7;
-    }
-
-    &--money {
-      color: #f4516c;
-    }
-
-    &--shopping {
-      color: #34bfa3;
-    }
-
-    &:hover {
-      :deep(.@{namespace}-icon) {
-        color: #fff !important;
-      }
-      .@{prefix-cls}__item--icon {
-        transition: all 0.38s ease-out;
-      }
-      .@{prefix-cls}__item--peoples {
-        background: #40c9c6;
-      }
-      .@{prefix-cls}__item--message {
-        background: #36a3f7;
-      }
-      .@{prefix-cls}__item--money {
-        background: #f4516c;
-      }
-      .@{prefix-cls}__item--shopping {
-        background: #34bfa3;
-      }
-    }
-  }
-}
-</style>

+ 235 - 290
yudao-ui-admin-vue3/src/views/Home/Index2.vue

@@ -1,197 +1,127 @@
 <script setup lang="ts">
-import { useTimeAgo } from '@/hooks/web/useTimeAgo'
-import { ElRow, ElCol, ElSkeleton, ElCard, ElDivider, ElLink } from 'element-plus'
-import { useI18n } from '@/hooks/web/useI18n'
 import { ref, reactive } from 'vue'
-import { CountTo } from '@/components/CountTo'
-import { formatTime } from '@/utils'
-import { Echart } from '@/components/Echart'
-import { EChartsOption } from 'echarts'
-import { radarOption } from './echarts-data'
-import { Highlight } from '@/components/Highlight'
-import type { WorkplaceTotal, Project, Dynamic, Team } from './types'
 import { set } from 'lodash-es'
-import { useCache } from '@/hooks/web/useCache'
+import { EChartsOption } from 'echarts'
+import { Echart } from '@/components/Echart'
+import { useI18n } from '@/hooks/web/useI18n'
+import { CountTo } from '@/components/CountTo'
+import type { AnalysisTotalTypes } from './types'
+import { useDesign } from '@/hooks/web/useDesign'
+import { ElRow, ElCol, ElCard, ElSkeleton } from 'element-plus'
+import { pieOptions, barOptions, lineOptions } from './echarts-data'
 
 const { t } = useI18n()
-const { wsCache } = useCache()
 const loading = ref(true)
-const avatar = wsCache.get('user').user.avatar
-const username = wsCache.get('user').user.nickname
-// 获取统计数
-let totalSate = reactive<WorkplaceTotal>({
-  project: 0,
-  access: 0,
-  todo: 0
+const { getPrefixCls } = useDesign()
+const prefixCls = getPrefixCls('panel')
+const pieOptionsData = reactive<EChartsOption>(pieOptions) as EChartsOption
+
+let totalState = reactive<AnalysisTotalTypes>({
+  users: 0,
+  messages: 0,
+  moneys: 0,
+  shoppings: 0
 })
 
 const getCount = async () => {
   const data = {
-    project: 40,
-    access: 2340,
-    todo: 10
+    users: 102400,
+    messages: 81212,
+    moneys: 9280,
+    shoppings: 13600
   }
-  totalSate = Object.assign(totalSate, data)
+  totalState = Object.assign(totalState, data)
 }
 
-let projects = reactive<Project[]>([])
-
-// 获取项目数
-const getProject = async () => {
+// 用户来源
+const getUserAccessSource = async () => {
   const data = [
-    {
-      name: 'Github',
-      icon: 'akar-icons:github-fill',
-      message: 'workplace.introduction',
-      personal: 'Archer',
-      time: new Date()
-    },
-    {
-      name: 'Vue',
-      icon: 'logos:vue',
-      message: 'workplace.introduction',
-      personal: 'Archer',
-      time: new Date()
-    },
-    {
-      name: 'Angular',
-      icon: 'logos:angular-icon',
-      message: 'workplace.introduction',
-      personal: 'Archer',
-      time: new Date()
-    },
-    {
-      name: 'React',
-      icon: 'logos:react',
-      message: 'workplace.introduction',
-      personal: 'Archer',
-      time: new Date()
-    },
-    {
-      name: 'Webpack',
-      icon: 'logos:webpack',
-      message: 'workplace.introduction',
-      personal: 'Archer',
-      time: new Date()
-    },
-    {
-      name: 'Vite',
-      icon: 'vscode-icons:file-type-vite',
-      message: 'workplace.introduction',
-      personal: 'Archer',
-      time: new Date()
-    }
+    { value: 335, name: 'analysis.directAccess' },
+    { value: 310, name: 'analysis.mailMarketing' },
+    { value: 234, name: 'analysis.allianceAdvertising' },
+    { value: 135, name: 'analysis.videoAdvertising' },
+    { value: 1548, name: 'analysis.searchEngines' }
   ]
-  projects = Object.assign(projects, data)
+  set(
+    pieOptionsData,
+    'legend.data',
+    data.map((v) => t(v.name))
+  )
+  set(pieOptionsData, 'series.data', data)
 }
+const barOptionsData = reactive<EChartsOption>(barOptions) as EChartsOption
 
-// 获取动态
-let dynamics = reactive<Dynamic[]>([])
-
-const getDynamic = async () => {
+// 周活跃量
+const getWeeklyUserActivity = async () => {
   const data = [
-    {
-      keys: ['workplace.push', 'Github'],
-      time: new Date()
-    },
-    {
-      keys: ['workplace.push', 'Github'],
-      time: new Date()
-    },
-    {
-      keys: ['workplace.push', 'Github'],
-      time: new Date()
-    },
-    {
-      keys: ['workplace.push', 'Github'],
-      time: new Date()
-    },
-    {
-      keys: ['workplace.push', 'Github'],
-      time: new Date()
-    },
-    {
-      keys: ['workplace.push', 'Github'],
-      time: new Date()
-    }
+    { value: 13253, name: 'analysis.monday' },
+    { value: 34235, name: 'analysis.tuesday' },
+    { value: 26321, name: 'analysis.wednesday' },
+    { value: 12340, name: 'analysis.thursday' },
+    { value: 24643, name: 'analysis.friday' },
+    { value: 1322, name: 'analysis.saturday' },
+    { value: 1324, name: 'analysis.sunday' }
   ]
-  dynamics = Object.assign(dynamics, data)
-}
-
-// 获取团队
-let team = reactive<Team[]>([])
-
-const getTeam = async () => {
-  const data = [
-    {
-      name: 'Github',
-      icon: 'akar-icons:github-fill'
-    },
-    {
-      name: 'Vue',
-      icon: 'logos:vue'
-    },
-    {
-      name: 'Angular',
-      icon: 'logos:angular-icon'
-    },
-    {
-      name: 'React',
-      icon: 'logos:react'
-    },
-    {
-      name: 'Webpack',
-      icon: 'logos:webpack'
-    },
+  set(
+    barOptionsData,
+    'xAxis.data',
+    data.map((v) => t(v.name))
+  )
+  set(barOptionsData, 'series', [
     {
-      name: 'Vite',
-      icon: 'vscode-icons:file-type-vite'
+      name: t('analysis.activeQuantity'),
+      data: data.map((v) => v.value),
+      type: 'bar'
     }
-  ]
-  team = Object.assign(team, data)
+  ])
 }
 
-// 获取指数
-let radarOptionData = reactive<EChartsOption>(radarOption) as EChartsOption
+const lineOptionsData = reactive<EChartsOption>(lineOptions) as EChartsOption
 
-const getRadar = async () => {
+// 每月销售总额
+const getMonthlySales = async () => {
   const data = [
-    { name: 'workplace.quote', max: 65, personal: 42, team: 50 },
-    { name: 'workplace.contribution', max: 160, personal: 30, team: 140 },
-    { name: 'workplace.hot', max: 300, personal: 20, team: 28 },
-    { name: 'workplace.yield', max: 130, personal: 35, team: 35 },
-    { name: 'workplace.follow', max: 100, personal: 80, team: 90 }
+    { estimate: 100, actual: 120, name: 'analysis.january' },
+    { estimate: 120, actual: 82, name: 'analysis.february' },
+    { estimate: 161, actual: 91, name: 'analysis.march' },
+    { estimate: 134, actual: 154, name: 'analysis.april' },
+    { estimate: 105, actual: 162, name: 'analysis.may' },
+    { estimate: 160, actual: 140, name: 'analysis.june' },
+    { estimate: 165, actual: 145, name: 'analysis.july' },
+    { estimate: 114, actual: 250, name: 'analysis.august' },
+    { estimate: 163, actual: 134, name: 'analysis.september' },
+    { estimate: 185, actual: 56, name: 'analysis.october' },
+    { estimate: 118, actual: 99, name: 'analysis.november' },
+    { estimate: 123, actual: 123, name: 'analysis.december' }
   ]
   set(
-    radarOptionData,
-    'radar.indicator',
-    data.map((v) => {
-      return {
-        name: t(v.name),
-        max: v.max
-      }
-    })
+    lineOptionsData,
+    'xAxis.data',
+    data.map((v) => t(v.name))
   )
-  set(radarOptionData, 'series', [
+  set(lineOptionsData, 'series', [
     {
-      name: '指数',
-      type: 'radar',
-      data: [
-        {
-          value: data.map((v) => v.personal),
-          name: t('workplace.personal')
-        },
-        {
-          value: data.map((v) => v.team),
-          name: t('workplace.team')
-        }
-      ]
+      name: t('analysis.estimate'),
+      smooth: true,
+      type: 'line',
+      data: data.map((v) => v.estimate),
+      animationDuration: 2800,
+      animationEasing: 'cubicInOut'
+    },
+    {
+      name: t('analysis.actual'),
+      smooth: true,
+      type: 'line',
+      itemStyle: {},
+      data: data.map((v) => v.actual),
+      animationDuration: 2800,
+      animationEasing: 'quadraticOut'
     }
   ])
 }
 
 const getAllApi = async () => {
-  await Promise.all([getCount(), getProject(), getDynamic(), getTeam(), getRadar()])
+  await Promise.all([getCount(), getUserAccessSource(), getWeeklyUserActivity(), getMonthlySales()])
   loading.value = false
 }
 
@@ -199,173 +129,188 @@ getAllApi()
 </script>
 
 <template>
-  <div>
-    <el-card shadow="never">
-      <el-skeleton :loading="loading" animated>
-        <el-row :gutter="20" justify="space-between">
-          <el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24">
-            <div class="flex items-center">
-              <img :src="avatar" alt="" class="w-70px h-70px rounded-[50%] mr-20px" />
+  <el-row :gutter="20" justify="space-between" :class="prefixCls">
+    <el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24">
+      <el-card shadow="hover" class="mb-20px">
+        <el-skeleton :loading="loading" animated :rows="2">
+          <template #default>
+            <div :class="`${prefixCls}__item flex justify-between`">
               <div>
-                <div class="text-20px text-700">
-                  {{ t('workplace.goodMorning') }} {{ username }} {{ t('workplace.happyDay') }}
-                </div>
-                <div class="mt-10px text-14px text-gray-500">
-                  {{ t('workplace.toady') }},20℃ - 32℃!
+                <div
+                  :class="`${prefixCls}__item--icon ${prefixCls}__item--peoples p-16px inline-block rounded-6px`"
+                >
+                  <Icon icon="svg-icon:peoples" :size="40" />
                 </div>
               </div>
-            </div>
-          </el-col>
-          <el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24">
-            <div class="flex h-70px items-center justify-end <sm:mt-20px">
-              <div class="px-8px text-right">
-                <div class="text-14px text-gray-400 mb-20px">{{ t('workplace.project') }}</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"
+                  class="text-20px font-700 text-right"
                   :start-val="0"
-                  :end-val="totalSate.project"
+                  :end-val="102400"
                   :duration="2600"
                 />
               </div>
-              <el-divider direction="vertical" />
-              <div class="px-8px text-right">
-                <div class="text-14px text-gray-400 mb-20px">{{ t('workplace.toDo') }}</div>
+            </div>
+          </template>
+        </el-skeleton>
+      </el-card>
+    </el-col>
+
+    <el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24">
+      <el-card shadow="hover" class="mb-20px">
+        <el-skeleton :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"
+                  class="text-20px font-700 text-right"
                   :start-val="0"
-                  :end-val="totalSate.todo"
+                  :end-val="81212"
                   :duration="2600"
                 />
               </div>
-              <el-divider direction="vertical" border-style="dashed" />
-              <div class="px-8px text-right">
-                <div class="text-14px text-gray-400 mb-20px">{{ t('workplace.access') }}</div>
+            </div>
+          </template>
+        </el-skeleton>
+      </el-card>
+    </el-col>
+
+    <el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24">
+      <el-card shadow="hover" class="mb-20px">
+        <el-skeleton :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"
+                  class="text-20px font-700 text-right"
                   :start-val="0"
-                  :end-val="totalSate.access"
+                  :end-val="9280"
                   :duration="2600"
                 />
               </div>
             </div>
-          </el-col>
-        </el-row>
-      </el-skeleton>
-    </el-card>
-  </div>
-
-  <el-row class="mt-20px" :gutter="20" justify="space-between">
-    <el-col :xl="16" :lg="16" :md="24" :sm="24" :xs="24" class="mb-20px">
-      <el-card shadow="never">
-        <template #header>
-          <div class="flex justify-between">
-            <span>{{ t('workplace.project') }}</span>
-            <ElLink type="primary" :underline="false">{{ t('workplace.more') }}</ElLink>
-          </div>
-        </template>
-        <el-skeleton :loading="loading" animated>
-          <el-row>
-            <el-col
-              v-for="(item, index) in projects"
-              :key="`card-${index}`"
-              :xl="8"
-              :lg="8"
-              :md="12"
-              :sm="24"
-              :xs="24"
-            >
-              <el-card shadow="hover">
-                <div class="flex items-center">
-                  <Icon :icon="item.icon" :size="25" class="mr-10px" />
-                  <span class="text-16px">{{ item.name }}</span>
-                </div>
-                <div class="mt-15px text-14px text-gray-400">{{ t(item.message) }}</div>
-                <div class="mt-20px text-12px text-gray-400 flex justify-between">
-                  <span>{{ item.personal }}</span>
-                  <span>{{ formatTime(item.time, 'yyyy-MM-dd') }}</span>
-                </div>
-              </el-card>
-            </el-col>
-          </el-row>
+          </template>
         </el-skeleton>
       </el-card>
+    </el-col>
 
-      <el-card shadow="never" class="mt-20px">
-        <template #header>
-          <div class="flex justify-between">
-            <span>{{ t('workplace.dynamic') }}</span>
-            <ElLink type="primary" :underline="false">{{ t('workplace.more') }}</ElLink>
-          </div>
-        </template>
-        <el-skeleton :loading="loading" animated>
-          <div v-for="(item, index) in dynamics" :key="`dynamics-${index}`">
-            <div class="flex items-center">
-              <img :src="avatar" alt="" class="w-35px h-35px rounded-[50%] mr-20px" />
+    <el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24">
+      <el-card shadow="hover" class="mb-20px">
+        <el-skeleton :loading="loading" animated :rows="2">
+          <template #default>
+            <div :class="`${prefixCls}__item flex justify-between`">
               <div>
-                <div class="text-14px">
-                  <Highlight :keys="item.keys.map((v) => t(v))">
-                    {{ username }} {{ t('workplace.pushCode') }}
-                  </Highlight>
-                </div>
-                <div class="mt-15px text-12px text-gray-400">
-                  {{ useTimeAgo(item.time) }}
+                <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>
-            <el-divider />
-          </div>
+          </template>
         </el-skeleton>
       </el-card>
     </el-col>
-    <el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24" class="mb-20px">
-      <el-card shadow="never">
-        <template #header>
-          <span>{{ t('workplace.shortcutOperation') }}</span>
-        </template>
+  </el-row>
+  <el-row :gutter="20" justify="space-between">
+    <el-col :xl="10" :lg="10" :md="24" :sm="24" :xs="24">
+      <el-card shadow="hover" class="mb-20px">
         <el-skeleton :loading="loading" animated>
-          <el-col
-            v-for="item in 9"
-            :key="`card-${item}`"
-            :xl="12"
-            :lg="12"
-            :md="12"
-            :sm="24"
-            :xs="24"
-            class="mb-10px"
-          >
-            <ElLink type="default" :underline="false">
-              {{ t('workplace.operation') }}{{ item }}
-            </ElLink>
-          </el-col>
+          <Echart :options="pieOptionsData" :height="300" />
         </el-skeleton>
       </el-card>
-
-      <el-card shadow="never" class="mt-20px">
-        <template #header>
-          <span>{{ t('workplace.index') }}</span>
-        </template>
+    </el-col>
+    <el-col :xl="14" :lg="14" :md="24" :sm="24" :xs="24">
+      <el-card shadow="hover" class="mb-20px">
         <el-skeleton :loading="loading" animated>
-          <Echart :options="radarOptionData" :height="400" />
+          <Echart :options="barOptionsData" :height="300" />
         </el-skeleton>
       </el-card>
-
-      <el-card shadow="never" class="mt-20px">
-        <template #header>
-          <span>{{ t('workplace.team') }}</span>
-        </template>
-        <el-skeleton :loading="loading" animated>
-          <el-row>
-            <el-col v-for="item in team" :key="`team-${item.name}`" :span="12" class="mb-20px">
-              <div class="flex items-center">
-                <Icon :icon="item.icon" class="mr-10px" />
-                <ElLink type="default" :underline="false">
-                  {{ item.name }}
-                </ElLink>
-              </div>
-            </el-col>
-          </el-row>
+    </el-col>
+    <el-col :span="24">
+      <el-card shadow="hover" class="mb-20px">
+        <el-skeleton :loading="loading" animated :rows="4">
+          <Echart :options="lineOptionsData" :height="350" />
         </el-skeleton>
       </el-card>
     </el-col>
   </el-row>
 </template>
+<style lang="less" scoped>
+@prefix-cls: ~'@{namespace}-panel';
+
+.@{prefix-cls} {
+  &__item {
+    &--peoples {
+      color: #40c9c6;
+    }
+
+    &--message {
+      color: #36a3f7;
+    }
+
+    &--money {
+      color: #f4516c;
+    }
+
+    &--shopping {
+      color: #34bfa3;
+    }
+
+    &:hover {
+      :deep(.@{namespace}-icon) {
+        color: #fff !important;
+      }
+      .@{prefix-cls}__item--icon {
+        transition: all 0.38s ease-out;
+      }
+      .@{prefix-cls}__item--peoples {
+        background: #40c9c6;
+      }
+      .@{prefix-cls}__item--message {
+        background: #36a3f7;
+      }
+      .@{prefix-cls}__item--money {
+        background: #f4516c;
+      }
+      .@{prefix-cls}__item--shopping {
+        background: #34bfa3;
+      }
+    }
+  }
+}
+</style>

+ 6 - 3
yudao-ui-admin-vue3/src/views/Home/types.ts

@@ -12,14 +12,17 @@ export type Project = {
   time: Date | number | string
 }
 
-export type Dynamic = {
+export type Notice = {
+  title: string
+  type: string
   keys: string[]
-  time: Date | number | string
+  date: Date | number | string
 }
 
-export type Team = {
+export type Shortcut = {
   name: string
   icon: string
+  url: string
 }
 
 export type RadarData = {