mirror of
				https://github.com/soybeanjs/soybean-admin.git
				synced 2025-11-04 15:53:43 +08:00 
			
		
		
		
	feat(projects): finish page home
This commit is contained in:
		
							
								
								
									
										
											BIN
										
									
								
								src/assets/imgs/soybean.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/assets/imgs/soybean.jpg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 112 KiB  | 
							
								
								
									
										7701
									
								
								src/assets/svg-icon/soybean.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7701
									
								
								src/assets/svg-icon/soybean.svg
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
		 After Width: | Height: | Size: 6.4 MiB  | 
							
								
								
									
										13
									
								
								src/components/custom/soybean-avatar.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/components/custom/soybean-avatar.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					defineOptions({
 | 
				
			||||||
 | 
					  name: 'SoybeanAvatar'
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div class="size-72px rd-1/2 overflow-hidden">
 | 
				
			||||||
 | 
					    <img src="@/assets/imgs/soybean.jpg" class="size-full" />
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped></style>
 | 
				
			||||||
@@ -186,6 +186,11 @@ const local: App.I18n.Schema = {
 | 
				
			|||||||
      devDep: 'Development Dependency'
 | 
					      devDep: 'Development Dependency'
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    home: {
 | 
					    home: {
 | 
				
			||||||
 | 
					      greeting: 'Good morning, {userName}, today is another day full of vitality!',
 | 
				
			||||||
 | 
					      weatherDesc: 'Today is cloudy to clear, 20℃ - 25℃!',
 | 
				
			||||||
 | 
					      projectCount: 'Project Count',
 | 
				
			||||||
 | 
					      todo: 'Todo',
 | 
				
			||||||
 | 
					      message: 'Message',
 | 
				
			||||||
      downloadCount: 'Download Count',
 | 
					      downloadCount: 'Download Count',
 | 
				
			||||||
      registerCount: 'Register Count',
 | 
					      registerCount: 'Register Count',
 | 
				
			||||||
      schedule: 'Work and rest Schedule',
 | 
					      schedule: 'Work and rest Schedule',
 | 
				
			||||||
@@ -193,9 +198,19 @@ const local: App.I18n.Schema = {
 | 
				
			|||||||
      work: 'Work',
 | 
					      work: 'Work',
 | 
				
			||||||
      rest: 'Rest',
 | 
					      rest: 'Rest',
 | 
				
			||||||
      entertainment: 'Entertainment',
 | 
					      entertainment: 'Entertainment',
 | 
				
			||||||
      visit: 'Visit Count',
 | 
					      visitCount: 'Visit Count',
 | 
				
			||||||
      amount: 'Amount',
 | 
					      turnover: 'Turnover',
 | 
				
			||||||
      trade: 'Trade Count'
 | 
					      dealCount: 'Deal Count',
 | 
				
			||||||
 | 
					      projectNews: {
 | 
				
			||||||
 | 
					        title: 'Project News',
 | 
				
			||||||
 | 
					        moreNews: 'More News',
 | 
				
			||||||
 | 
					        desc1: 'Soybean created the open source project soybean-admin on May 28, 2021!',
 | 
				
			||||||
 | 
					        desc2: 'Yanbowe submitted a bug to soybean-admin, the multi-tab bar will not adapt.',
 | 
				
			||||||
 | 
					        desc3: 'Soybean is ready to do sufficient preparation for the release of soybean-admin!',
 | 
				
			||||||
 | 
					        desc4: 'Soybean is busy writing project documentation for soybean-admin!',
 | 
				
			||||||
 | 
					        desc5: 'Soybean just wrote some of the workbench pages casually, and it was enough to see!'
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      creativity: 'Creativity'
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  form: {
 | 
					  form: {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -186,6 +186,11 @@ const local: App.I18n.Schema = {
 | 
				
			|||||||
      devDep: '开发依赖'
 | 
					      devDep: '开发依赖'
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    home: {
 | 
					    home: {
 | 
				
			||||||
 | 
					      greeting: '早安,{userName}, 今天又是充满活力的一天!',
 | 
				
			||||||
 | 
					      weatherDesc: '今日多云转晴,20℃ - 25℃!',
 | 
				
			||||||
 | 
					      projectCount: '项目数',
 | 
				
			||||||
 | 
					      todo: '待办',
 | 
				
			||||||
 | 
					      message: '消息',
 | 
				
			||||||
      downloadCount: '下载量',
 | 
					      downloadCount: '下载量',
 | 
				
			||||||
      registerCount: '注册量',
 | 
					      registerCount: '注册量',
 | 
				
			||||||
      schedule: '作息安排',
 | 
					      schedule: '作息安排',
 | 
				
			||||||
@@ -193,9 +198,19 @@ const local: App.I18n.Schema = {
 | 
				
			|||||||
      work: '工作',
 | 
					      work: '工作',
 | 
				
			||||||
      rest: '休息',
 | 
					      rest: '休息',
 | 
				
			||||||
      entertainment: '娱乐',
 | 
					      entertainment: '娱乐',
 | 
				
			||||||
      visit: '访问量',
 | 
					      visitCount: '访问量',
 | 
				
			||||||
      amount: '成交额',
 | 
					      turnover: '成交额',
 | 
				
			||||||
      trade: '成交量'
 | 
					      dealCount: '成交量',
 | 
				
			||||||
 | 
					      projectNews: {
 | 
				
			||||||
 | 
					        title: '项目动态',
 | 
				
			||||||
 | 
					        moreNews: '更多动态',
 | 
				
			||||||
 | 
					        desc1: 'Soybean 在2021年5月28日创建了开源项目 soybean-admin!',
 | 
				
			||||||
 | 
					        desc2: 'Yanbowe 向 soybean-admin 提交了一个bug,多标签栏不会自适应。',
 | 
				
			||||||
 | 
					        desc3: 'Soybean 准备为 soybean-admin 的发布做充分的准备工作!',
 | 
				
			||||||
 | 
					        desc4: 'Soybean 正在忙于为soybean-admin写项目说明文档!',
 | 
				
			||||||
 | 
					        desc5: 'Soybean 刚才把工作台页面随便写了一些,凑合能看了!'
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      creativity: '创意'
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  form: {
 | 
					  form: {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										21
									
								
								src/typings/app.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								src/typings/app.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -370,6 +370,11 @@ declare namespace App {
 | 
				
			|||||||
          devDep: string;
 | 
					          devDep: string;
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        home: {
 | 
					        home: {
 | 
				
			||||||
 | 
					          greeting: string;
 | 
				
			||||||
 | 
					          weatherDesc: string;
 | 
				
			||||||
 | 
					          projectCount: string;
 | 
				
			||||||
 | 
					          todo: string;
 | 
				
			||||||
 | 
					          message: string;
 | 
				
			||||||
          downloadCount: string;
 | 
					          downloadCount: string;
 | 
				
			||||||
          registerCount: string;
 | 
					          registerCount: string;
 | 
				
			||||||
          schedule: string;
 | 
					          schedule: string;
 | 
				
			||||||
@@ -377,9 +382,19 @@ declare namespace App {
 | 
				
			|||||||
          work: string;
 | 
					          work: string;
 | 
				
			||||||
          rest: string;
 | 
					          rest: string;
 | 
				
			||||||
          entertainment: string;
 | 
					          entertainment: string;
 | 
				
			||||||
          visit: string;
 | 
					          visitCount: string;
 | 
				
			||||||
          amount: string;
 | 
					          turnover: string;
 | 
				
			||||||
          trade: string;
 | 
					          dealCount: string;
 | 
				
			||||||
 | 
					          projectNews: {
 | 
				
			||||||
 | 
					            title: string;
 | 
				
			||||||
 | 
					            moreNews: string;
 | 
				
			||||||
 | 
					            desc1: string;
 | 
				
			||||||
 | 
					            desc2: string;
 | 
				
			||||||
 | 
					            desc3: string;
 | 
				
			||||||
 | 
					            desc4: string;
 | 
				
			||||||
 | 
					            desc5: string;
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          creativity: string;
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
      form: {
 | 
					      form: {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										6
									
								
								src/typings/components.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								src/typings/components.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -17,6 +17,7 @@ declare module 'vue' {
 | 
				
			|||||||
    IconAntDesignReloadOutlined: typeof import('~icons/ant-design/reload-outlined')['default']
 | 
					    IconAntDesignReloadOutlined: typeof import('~icons/ant-design/reload-outlined')['default']
 | 
				
			||||||
    IconGridiconsFullscreen: typeof import('~icons/gridicons/fullscreen')['default']
 | 
					    IconGridiconsFullscreen: typeof import('~icons/gridicons/fullscreen')['default']
 | 
				
			||||||
    IconGridiconsFullscreenExit: typeof import('~icons/gridicons/fullscreen-exit')['default']
 | 
					    IconGridiconsFullscreenExit: typeof import('~icons/gridicons/fullscreen-exit')['default']
 | 
				
			||||||
 | 
					    IconLocalBanner: typeof import('~icons/local/banner')['default']
 | 
				
			||||||
    IconLocalLogo: typeof import('~icons/local/logo')['default']
 | 
					    IconLocalLogo: typeof import('~icons/local/logo')['default']
 | 
				
			||||||
    LangSwitch: typeof import('./../components/common/lang-switch.vue')['default']
 | 
					    LangSwitch: typeof import('./../components/common/lang-switch.vue')['default']
 | 
				
			||||||
    LookForward: typeof import('./../components/custom/look-forward.vue')['default']
 | 
					    LookForward: typeof import('./../components/custom/look-forward.vue')['default']
 | 
				
			||||||
@@ -41,21 +42,26 @@ declare module 'vue' {
 | 
				
			|||||||
    NGridItem: typeof import('naive-ui')['NGridItem']
 | 
					    NGridItem: typeof import('naive-ui')['NGridItem']
 | 
				
			||||||
    NInput: typeof import('naive-ui')['NInput']
 | 
					    NInput: typeof import('naive-ui')['NInput']
 | 
				
			||||||
    NInputNumber: typeof import('naive-ui')['NInputNumber']
 | 
					    NInputNumber: typeof import('naive-ui')['NInputNumber']
 | 
				
			||||||
 | 
					    NList: typeof import('naive-ui')['NList']
 | 
				
			||||||
 | 
					    NListItem: typeof import('naive-ui')['NListItem']
 | 
				
			||||||
    NLoadingBarProvider: typeof import('naive-ui')['NLoadingBarProvider']
 | 
					    NLoadingBarProvider: typeof import('naive-ui')['NLoadingBarProvider']
 | 
				
			||||||
    NMenu: typeof import('naive-ui')['NMenu']
 | 
					    NMenu: typeof import('naive-ui')['NMenu']
 | 
				
			||||||
    NMessageProvider: typeof import('naive-ui')['NMessageProvider']
 | 
					    NMessageProvider: typeof import('naive-ui')['NMessageProvider']
 | 
				
			||||||
    NNotificationProvider: typeof import('naive-ui')['NNotificationProvider']
 | 
					    NNotificationProvider: typeof import('naive-ui')['NNotificationProvider']
 | 
				
			||||||
    NSelect: typeof import('naive-ui')['NSelect']
 | 
					    NSelect: typeof import('naive-ui')['NSelect']
 | 
				
			||||||
    NSpace: typeof import('naive-ui')['NSpace']
 | 
					    NSpace: typeof import('naive-ui')['NSpace']
 | 
				
			||||||
 | 
					    NStatistic: typeof import('naive-ui')['NStatistic']
 | 
				
			||||||
    NSwitch: typeof import('naive-ui')['NSwitch']
 | 
					    NSwitch: typeof import('naive-ui')['NSwitch']
 | 
				
			||||||
    NTab: typeof import('naive-ui')['NTab']
 | 
					    NTab: typeof import('naive-ui')['NTab']
 | 
				
			||||||
    NTabs: typeof import('naive-ui')['NTabs']
 | 
					    NTabs: typeof import('naive-ui')['NTabs']
 | 
				
			||||||
    NTag: typeof import('naive-ui')['NTag']
 | 
					    NTag: typeof import('naive-ui')['NTag']
 | 
				
			||||||
 | 
					    NThing: typeof import('naive-ui')['NThing']
 | 
				
			||||||
    NTooltip: typeof import('naive-ui')['NTooltip']
 | 
					    NTooltip: typeof import('naive-ui')['NTooltip']
 | 
				
			||||||
    PinToggler: typeof import('./../components/common/pin-toggler.vue')['default']
 | 
					    PinToggler: typeof import('./../components/common/pin-toggler.vue')['default']
 | 
				
			||||||
    ReloadButton: typeof import('./../components/common/reload-button.vue')['default']
 | 
					    ReloadButton: typeof import('./../components/common/reload-button.vue')['default']
 | 
				
			||||||
    RouterLink: typeof import('vue-router')['RouterLink']
 | 
					    RouterLink: typeof import('vue-router')['RouterLink']
 | 
				
			||||||
    RouterView: typeof import('vue-router')['RouterView']
 | 
					    RouterView: typeof import('vue-router')['RouterView']
 | 
				
			||||||
 | 
					    SoybeanAvatar: typeof import('./../components/custom/soybean-avatar.vue')['default']
 | 
				
			||||||
    SvgIcon: typeof import('./../components/custom/svg-icon.vue')['default']
 | 
					    SvgIcon: typeof import('./../components/custom/svg-icon.vue')['default']
 | 
				
			||||||
    SystemLogo: typeof import('./../components/common/system-logo.vue')['default']
 | 
					    SystemLogo: typeof import('./../components/common/system-logo.vue')['default']
 | 
				
			||||||
    ThemeSchemaSwitch: typeof import('./../components/common/theme-schema-switch.vue')['default']
 | 
					    ThemeSchemaSwitch: typeof import('./../components/common/theme-schema-switch.vue')['default']
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										109
									
								
								src/views/home/components/card-data.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								src/views/home/components/card-data.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,109 @@
 | 
				
			|||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import { computed } from 'vue';
 | 
				
			||||||
 | 
					import { createReusableTemplate } from '@vueuse/core';
 | 
				
			||||||
 | 
					import { $t } from '@/locales';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defineOptions({
 | 
				
			||||||
 | 
					  name: 'CardData'
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface CardData {
 | 
				
			||||||
 | 
					  key: string;
 | 
				
			||||||
 | 
					  title: string;
 | 
				
			||||||
 | 
					  value: number;
 | 
				
			||||||
 | 
					  unit: string;
 | 
				
			||||||
 | 
					  color: {
 | 
				
			||||||
 | 
					    start: string;
 | 
				
			||||||
 | 
					    end: string;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  icon: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const cardData = computed<CardData[]>(() => [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    key: 'visitCount',
 | 
				
			||||||
 | 
					    title: $t('page.home.visitCount'),
 | 
				
			||||||
 | 
					    value: 9725,
 | 
				
			||||||
 | 
					    unit: '',
 | 
				
			||||||
 | 
					    color: {
 | 
				
			||||||
 | 
					      start: '#ec4786',
 | 
				
			||||||
 | 
					      end: '#b955a4'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    icon: 'ant-design:bar-chart-outlined'
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    key: 'turnover',
 | 
				
			||||||
 | 
					    title: $t('page.home.turnover'),
 | 
				
			||||||
 | 
					    value: 1026,
 | 
				
			||||||
 | 
					    unit: '$',
 | 
				
			||||||
 | 
					    color: {
 | 
				
			||||||
 | 
					      start: '#865ec0',
 | 
				
			||||||
 | 
					      end: '#5144b4'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    icon: 'ant-design:money-collect-outlined'
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    key: 'downloadCount',
 | 
				
			||||||
 | 
					    title: $t('page.home.downloadCount'),
 | 
				
			||||||
 | 
					    value: 970925,
 | 
				
			||||||
 | 
					    unit: '',
 | 
				
			||||||
 | 
					    color: {
 | 
				
			||||||
 | 
					      start: '#56cdf3',
 | 
				
			||||||
 | 
					      end: '#719de3'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    icon: 'carbon:document-download'
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    key: 'dealCount',
 | 
				
			||||||
 | 
					    title: $t('page.home.dealCount'),
 | 
				
			||||||
 | 
					    value: 9527,
 | 
				
			||||||
 | 
					    unit: '',
 | 
				
			||||||
 | 
					    color: {
 | 
				
			||||||
 | 
					      start: '#fcbc25',
 | 
				
			||||||
 | 
					      end: '#f68057'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    icon: 'ant-design:trademark-circle-outlined'
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface GradientBgProps {
 | 
				
			||||||
 | 
					  gradientColor: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const [DefineGradientBg, GradientBg] = createReusableTemplate<GradientBgProps>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function getGradientColor(color: CardData['color']) {
 | 
				
			||||||
 | 
					  return `linear-gradient(to bottom right, ${color.start}, ${color.end})`;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <NCard :bordered="false" class="card-wrapper">
 | 
				
			||||||
 | 
					    <!-- define component start: GradientBg -->
 | 
				
			||||||
 | 
					    <DefineGradientBg v-slot="{ $slots, gradientColor }">
 | 
				
			||||||
 | 
					      <div class="px-16px pt-8px pb-4px rd-8px text-white" :style="{ backgroundImage: gradientColor }">
 | 
				
			||||||
 | 
					        <component :is="$slots.default" />
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </DefineGradientBg>
 | 
				
			||||||
 | 
					    <!-- define component end: GradientBg -->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <NGrid cols="s:1 m:2 l:4" responsive="screen" :x-gap="16" :y-gap="16">
 | 
				
			||||||
 | 
					      <NGi v-for="item in cardData" :key="item.key">
 | 
				
			||||||
 | 
					        <GradientBg :gradient-color="getGradientColor(item.color)" class="flex-1">
 | 
				
			||||||
 | 
					          <h3 class="text-16px">{{ item.title }}</h3>
 | 
				
			||||||
 | 
					          <div class="flex justify-between pt-12px">
 | 
				
			||||||
 | 
					            <SvgIcon :icon="item.icon" class="text-32px" />
 | 
				
			||||||
 | 
					            <CountTo
 | 
				
			||||||
 | 
					              :prefix="item.unit"
 | 
				
			||||||
 | 
					              :start-value="1"
 | 
				
			||||||
 | 
					              :end-value="item.value"
 | 
				
			||||||
 | 
					              class="text-30px text-white dark:text-dark"
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </GradientBg>
 | 
				
			||||||
 | 
					      </NGi>
 | 
				
			||||||
 | 
					    </NGrid>
 | 
				
			||||||
 | 
					  </NCard>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped></style>
 | 
				
			||||||
@@ -1,27 +0,0 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					 | 
				
			||||||
import { computed } from 'vue';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
defineOptions({
 | 
					 | 
				
			||||||
  name: 'GradientBg'
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const props = withDefaults(defineProps<Props>(), {
 | 
					 | 
				
			||||||
  startColor: '#56cdf3',
 | 
					 | 
				
			||||||
  endColor: '#719de3'
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
interface Props {
 | 
					 | 
				
			||||||
  startColor?: string;
 | 
					 | 
				
			||||||
  endColor?: string;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const gradientStyle = computed(() => `linear-gradient(to bottom right, ${props.startColor}, ${props.endColor})`);
 | 
					 | 
				
			||||||
</script>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<template>
 | 
					 | 
				
			||||||
  <div class="px-16px pt-8px pb-4px rd-8px text-white" :style="{ backgroundImage: gradientStyle }">
 | 
					 | 
				
			||||||
    <slot></slot>
 | 
					 | 
				
			||||||
  </div>
 | 
					 | 
				
			||||||
</template>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<style scoped></style>
 | 
					 | 
				
			||||||
							
								
								
									
										66
									
								
								src/views/home/components/header-banner.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								src/views/home/components/header-banner.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
				
			|||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import { computed } from 'vue';
 | 
				
			||||||
 | 
					import { $t } from '@/locales';
 | 
				
			||||||
 | 
					import { useAppStore } from '@/store/modules/app';
 | 
				
			||||||
 | 
					import { useAuthStore } from '@/store/modules/auth';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defineOptions({
 | 
				
			||||||
 | 
					  name: 'HeaderBanner'
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const appStore = useAppStore();
 | 
				
			||||||
 | 
					const authStore = useAuthStore();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const gap = computed(() => (appStore.isMobile ? 0 : 16));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface StatisticData {
 | 
				
			||||||
 | 
					  id: number;
 | 
				
			||||||
 | 
					  label: string;
 | 
				
			||||||
 | 
					  value: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const statisticData = computed<StatisticData[]>(() => [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    id: 0,
 | 
				
			||||||
 | 
					    label: $t('page.home.projectCount'),
 | 
				
			||||||
 | 
					    value: '25'
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    id: 1,
 | 
				
			||||||
 | 
					    label: $t('page.home.todo'),
 | 
				
			||||||
 | 
					    value: '4/16'
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    id: 2,
 | 
				
			||||||
 | 
					    label: $t('page.home.message'),
 | 
				
			||||||
 | 
					    value: '12'
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					]);
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <NCard :bordered="false" class="card-wrapper">
 | 
				
			||||||
 | 
					    <NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive>
 | 
				
			||||||
 | 
					      <NGi span="24 s:24 m:20">
 | 
				
			||||||
 | 
					        <div class="flex-y-center">
 | 
				
			||||||
 | 
					          <div class="shrink-0 size-72px rd-1/2 overflow-hidden">
 | 
				
			||||||
 | 
					            <img src="@/assets/imgs/soybean.jpg" class="size-full" />
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div class="pl-12px">
 | 
				
			||||||
 | 
					            <h3 class="text-18px font-semibold">
 | 
				
			||||||
 | 
					              {{ $t('page.home.greeting', { userName: authStore.userInfo.userName }) }}
 | 
				
			||||||
 | 
					            </h3>
 | 
				
			||||||
 | 
					            <p class="leading-30px text-#999">{{ $t('page.home.weatherDesc') }}</p>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </NGi>
 | 
				
			||||||
 | 
					      <NGi span="24 s:24 m:4">
 | 
				
			||||||
 | 
					        <NSpace :size="24" justify="end">
 | 
				
			||||||
 | 
					          <NStatistic v-for="item in statisticData" :key="item.id" class="whitespace-nowrap" v-bind="item" />
 | 
				
			||||||
 | 
					        </NSpace>
 | 
				
			||||||
 | 
					      </NGi>
 | 
				
			||||||
 | 
					    </NGrid>
 | 
				
			||||||
 | 
					  </NCard>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped></style>
 | 
				
			||||||
							
								
								
									
										40
									
								
								src/views/home/components/project-news.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/views/home/components/project-news.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import { computed } from 'vue';
 | 
				
			||||||
 | 
					import { $t } from '@/locales';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defineOptions({
 | 
				
			||||||
 | 
					  name: 'ProjectNews'
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface NewsItem {
 | 
				
			||||||
 | 
					  id: number;
 | 
				
			||||||
 | 
					  content: string;
 | 
				
			||||||
 | 
					  time: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const newses = computed<NewsItem[]>(() => [
 | 
				
			||||||
 | 
					  { id: 1, content: $t('page.home.projectNews.desc1'), time: '2021-05-28 22:22:22' },
 | 
				
			||||||
 | 
					  { id: 2, content: $t('page.home.projectNews.desc2'), time: '2021-10-27 10:24:54' },
 | 
				
			||||||
 | 
					  { id: 3, content: $t('page.home.projectNews.desc3'), time: '2021-10-31 22:43:12' },
 | 
				
			||||||
 | 
					  { id: 4, content: $t('page.home.projectNews.desc4'), time: '2021-11-03 20:33:31' },
 | 
				
			||||||
 | 
					  { id: 5, content: $t('page.home.projectNews.desc5'), time: '2021-11-07 22:45:32' }
 | 
				
			||||||
 | 
					]);
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <NCard :title="$t('page.home.projectNews.title')" :bordered="false" size="small" segmented class="card-wrapper">
 | 
				
			||||||
 | 
					    <template #header-extra>
 | 
				
			||||||
 | 
					      <a class="text-primary" href="javascript:;">{{ $t('page.home.projectNews.moreNews') }}</a>
 | 
				
			||||||
 | 
					    </template>
 | 
				
			||||||
 | 
					    <NList>
 | 
				
			||||||
 | 
					      <NListItem v-for="item in newses" :key="item.id">
 | 
				
			||||||
 | 
					        <template #prefix>
 | 
				
			||||||
 | 
					          <SoybeanAvatar class="size-48px!" />
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					        <NThing :title="item.content" :description="item.time" />
 | 
				
			||||||
 | 
					      </NListItem>
 | 
				
			||||||
 | 
					    </NList>
 | 
				
			||||||
 | 
					  </NCard>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped></style>
 | 
				
			||||||
@@ -3,7 +3,9 @@ import { computed, watch } from 'vue';
 | 
				
			|||||||
import { $t } from '@/locales';
 | 
					import { $t } from '@/locales';
 | 
				
			||||||
import { useAppStore } from '@/store/modules/app';
 | 
					import { useAppStore } from '@/store/modules/app';
 | 
				
			||||||
import { useEcharts } from '@/hooks/chart/use-echarts';
 | 
					import { useEcharts } from '@/hooks/chart/use-echarts';
 | 
				
			||||||
import GradientBg from './components/gradient-bg.vue';
 | 
					import HeaderBanner from './components/header-banner.vue';
 | 
				
			||||||
 | 
					import CardData from './components/card-data.vue';
 | 
				
			||||||
 | 
					import ProjectNews from './components/project-news.vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const appStore = useAppStore();
 | 
					const appStore = useAppStore();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -201,50 +203,6 @@ function updatePieLocale() {
 | 
				
			|||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface CardData {
 | 
					 | 
				
			||||||
  key: string;
 | 
					 | 
				
			||||||
  title: string;
 | 
					 | 
				
			||||||
  value: number;
 | 
					 | 
				
			||||||
  unit: string;
 | 
					 | 
				
			||||||
  colors: [string, string];
 | 
					 | 
				
			||||||
  icon: string;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const cardData = computed<CardData[]>(() => [
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    key: 'visit',
 | 
					 | 
				
			||||||
    title: $t('page.home.visit'),
 | 
					 | 
				
			||||||
    value: 1000000,
 | 
					 | 
				
			||||||
    unit: '',
 | 
					 | 
				
			||||||
    colors: ['#ec4786', '#b955a4'],
 | 
					 | 
				
			||||||
    icon: 'ant-design:bar-chart-outlined'
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    key: 'amount',
 | 
					 | 
				
			||||||
    title: $t('page.home.amount'),
 | 
					 | 
				
			||||||
    value: 234567.89,
 | 
					 | 
				
			||||||
    unit: '$',
 | 
					 | 
				
			||||||
    colors: ['#865ec0', '#5144b4'],
 | 
					 | 
				
			||||||
    icon: 'ant-design:money-collect-outlined'
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    key: 'download',
 | 
					 | 
				
			||||||
    title: $t('page.home.downloadCount'),
 | 
					 | 
				
			||||||
    value: 666666,
 | 
					 | 
				
			||||||
    unit: '',
 | 
					 | 
				
			||||||
    colors: ['#56cdf3', '#719de3'],
 | 
					 | 
				
			||||||
    icon: 'carbon:document-download'
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    key: 'trade',
 | 
					 | 
				
			||||||
    title: $t('page.home.trade'),
 | 
					 | 
				
			||||||
    value: 999999,
 | 
					 | 
				
			||||||
    unit: '',
 | 
					 | 
				
			||||||
    colors: ['#fcbc25', '#f68057'],
 | 
					 | 
				
			||||||
    icon: 'ant-design:trademark-circle-outlined'
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async function init() {
 | 
					async function init() {
 | 
				
			||||||
  mockLineData();
 | 
					  mockLineData();
 | 
				
			||||||
  mockPieData();
 | 
					  mockPieData();
 | 
				
			||||||
@@ -264,53 +222,32 @@ init();
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <NSpace vertical :size="16">
 | 
					  <NSpace vertical :size="16">
 | 
				
			||||||
 | 
					    <HeaderBanner />
 | 
				
			||||||
    <NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive>
 | 
					    <NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive>
 | 
				
			||||||
      <NGi span="24 s:24 m:6">
 | 
					      <NGi span="24 s:24 m:14">
 | 
				
			||||||
        <NCard :bordered="false" class="card-wrapper">
 | 
					 | 
				
			||||||
          <div class="w-full h-360px py-12px">
 | 
					 | 
				
			||||||
            <h3 class="text-16px font-bold">Dashboard</h3>
 | 
					 | 
				
			||||||
            <p class="text-#aaa">Overview Of Lasted Month</p>
 | 
					 | 
				
			||||||
            <h3 class="pt-32px text-24px font-bold">
 | 
					 | 
				
			||||||
              <CountTo prefix="$" :start-value="0" :end-value="7754" />
 | 
					 | 
				
			||||||
            </h3>
 | 
					 | 
				
			||||||
            <p class="text-#aaa">Current Month Earnings</p>
 | 
					 | 
				
			||||||
            <h3 class="pt-32px text-24px font-bold">
 | 
					 | 
				
			||||||
              <CountTo :start-value="0" :end-value="1234" />
 | 
					 | 
				
			||||||
            </h3>
 | 
					 | 
				
			||||||
            <p class="text-#aaa">Current Month Sales</p>
 | 
					 | 
				
			||||||
            <NButton class="mt-24px whitespace-pre-wrap" type="primary">Last Month Summary</NButton>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </NCard>
 | 
					 | 
				
			||||||
      </NGi>
 | 
					 | 
				
			||||||
      <NGi span="24 s:24 m:10">
 | 
					 | 
				
			||||||
        <NCard :bordered="false" class="card-wrapper">
 | 
					        <NCard :bordered="false" class="card-wrapper">
 | 
				
			||||||
          <div ref="lineRef" class="h-360px overflow-hidden"></div>
 | 
					          <div ref="lineRef" class="h-360px overflow-hidden"></div>
 | 
				
			||||||
        </NCard>
 | 
					        </NCard>
 | 
				
			||||||
      </NGi>
 | 
					      </NGi>
 | 
				
			||||||
      <NGi span="24 s:24 m:8">
 | 
					      <NGi span="24 s:24 m:10">
 | 
				
			||||||
        <NCard :bordered="false" class="card-wrapper">
 | 
					        <NCard :bordered="false" class="card-wrapper">
 | 
				
			||||||
          <div ref="pieRef" class="h-360px"></div>
 | 
					          <div ref="pieRef" class="h-360px"></div>
 | 
				
			||||||
        </NCard>
 | 
					        </NCard>
 | 
				
			||||||
      </NGi>
 | 
					      </NGi>
 | 
				
			||||||
    </NGrid>
 | 
					    </NGrid>
 | 
				
			||||||
    <NCard :bordered="false" class="card-wrapper">
 | 
					    <CardData />
 | 
				
			||||||
      <NGrid cols="s:1 m:2 l:4" responsive="screen" :x-gap="16" :y-gap="16">
 | 
					    <NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive>
 | 
				
			||||||
        <NGi v-for="item in cardData" :key="item.key">
 | 
					      <NGi span="24 s:24 m:14">
 | 
				
			||||||
          <GradientBg :start-color="item.colors[0]" :end-color="item.colors[1]" class="flex-1">
 | 
					        <ProjectNews />
 | 
				
			||||||
            <h3 class="text-16px">{{ item.title }}</h3>
 | 
					      </NGi>
 | 
				
			||||||
            <div class="flex justify-between pt-12px">
 | 
					      <NGi span="24 s:24 m:10">
 | 
				
			||||||
              <SvgIcon :icon="item.icon" class="text-32px" />
 | 
					        <NCard :title="$t('page.home.creativity')" :bordered="false" size="small" class="card-wrapper h-full">
 | 
				
			||||||
              <CountTo
 | 
					          <div class="flex-center h-full">
 | 
				
			||||||
                :prefix="item.unit"
 | 
					            <IconLocalBanner class="text-400px sm:text-320px text-primary" />
 | 
				
			||||||
                :start-value="1"
 | 
					          </div>
 | 
				
			||||||
                :end-value="item.value"
 | 
					        </NCard>
 | 
				
			||||||
                class="text-30px text-white dark:text-dark"
 | 
					      </NGi>
 | 
				
			||||||
              />
 | 
					    </NGrid>
 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
          </GradientBg>
 | 
					 | 
				
			||||||
        </NGi>
 | 
					 | 
				
			||||||
      </NGrid>
 | 
					 | 
				
			||||||
    </NCard>
 | 
					 | 
				
			||||||
  </NSpace>
 | 
					  </NSpace>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user