mirror of
https://github.com/soybeanjs/soybean-admin.git
synced 2025-09-21 11:06:38 +08:00
feat(projects): 分析页更新,添加关于页面
This commit is contained in:
parent
7527b1f07c
commit
8e18218196
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -47,7 +47,7 @@
|
|||||||
"[vue]": {
|
"[vue]": {
|
||||||
"editor.defaultFormatter": "johnsoncodehk.volar"
|
"editor.defaultFormatter": "johnsoncodehk.volar"
|
||||||
},
|
},
|
||||||
"terminal.integrated.tabs.enabled": false,
|
"terminal.integrated.tabs.enabled": true,
|
||||||
"[typescriptreact]": {
|
"[typescriptreact]": {
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
},
|
},
|
||||||
|
@ -12,7 +12,7 @@ class类名的顺序:
|
|||||||
|
|
||||||
例如:自定义类名结合tailwind css
|
例如:自定义类名结合tailwind css
|
||||||
|
|
||||||
<div class="demo-container absolute flex justify-center items-center left-10px top-12px overflow-hidden w-full h-full p-10px border-1px border-[#f00] m-24px bg-[#fff] text-32px text-[#0f0]"></div>
|
<div class="demo-container absolute flex justify-center items-center left-10px top-12px overflow-hidden wh-full p-10px border-1px border-[#f00] m-24px bg-[#fff] text-32px text-[#0f0]"></div>
|
||||||
<style>
|
<style>
|
||||||
.demo-container {
|
.demo-container {
|
||||||
box-shadow: 2px 0 8px 0 rgb(29 35 41 / 5%);
|
box-shadow: 2px 0 8px 0 rgb(29 35 41 / 5%);
|
||||||
|
15
package.json
15
package.json
@ -18,15 +18,16 @@
|
|||||||
"*.{vue,js,jsx,ts,tsx}": "eslint --fix"
|
"*.{vue,js,jsx,ts,tsx}": "eslint --fix"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@antv/g2plot": "^2.3.39",
|
||||||
"@better-scroll/core": "^2.4.2",
|
"@better-scroll/core": "^2.4.2",
|
||||||
"@vueuse/core": "^6.7.4",
|
"@vueuse/core": "^6.7.5",
|
||||||
"axios": "^0.24.0",
|
"axios": "^0.24.0",
|
||||||
"chroma-js": "^2.1.2",
|
"chroma-js": "^2.1.2",
|
||||||
"clipboard": "^2.0.8",
|
"clipboard": "^2.0.8",
|
||||||
"dayjs": "^1.10.7",
|
"dayjs": "^1.10.7",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
"naive-ui": "^2.20.1",
|
"naive-ui": "^2.20.1",
|
||||||
"pinia": "^2.0.0",
|
"pinia": "^2.0.2",
|
||||||
"qs": "^6.10.1",
|
"qs": "^6.10.1",
|
||||||
"vue": "^3.2.20",
|
"vue": "^3.2.20",
|
||||||
"vue-router": "^4.0.11"
|
"vue-router": "^4.0.11"
|
||||||
@ -34,7 +35,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^14.1.0",
|
"@commitlint/cli": "^14.1.0",
|
||||||
"@commitlint/config-conventional": "^14.1.0",
|
"@commitlint/config-conventional": "^14.1.0",
|
||||||
"@iconify/json": "^1.1.417",
|
"@iconify/json": "^1.1.423",
|
||||||
"@iconify/vue": "^3.0.0",
|
"@iconify/vue": "^3.0.0",
|
||||||
"@types/chroma-js": "^2.1.3",
|
"@types/chroma-js": "^2.1.3",
|
||||||
"@types/qs": "^6.9.7",
|
"@types/qs": "^6.9.7",
|
||||||
@ -51,7 +52,7 @@
|
|||||||
"@vitejs/plugin-vue": "^1.9.4",
|
"@vitejs/plugin-vue": "^1.9.4",
|
||||||
"@vue/compiler-sfc": "^3.2.21",
|
"@vue/compiler-sfc": "^3.2.21",
|
||||||
"@vue/eslint-config-prettier": "^6.0.0",
|
"@vue/eslint-config-prettier": "^6.0.0",
|
||||||
"@vue/eslint-config-typescript": "^9.0.0",
|
"@vue/eslint-config-typescript": "^9.0.1",
|
||||||
"commitizen": "^4.2.4",
|
"commitizen": "^4.2.4",
|
||||||
"cz-conventional-changelog": "^3.3.0",
|
"cz-conventional-changelog": "^3.3.0",
|
||||||
"cz-customizable": "^6.3.0",
|
"cz-customizable": "^6.3.0",
|
||||||
@ -70,14 +71,14 @@
|
|||||||
"rollup-plugin-visualizer": "^5.5.2",
|
"rollup-plugin-visualizer": "^5.5.2",
|
||||||
"sass": "^1.43.4",
|
"sass": "^1.43.4",
|
||||||
"typescript": "^4.4.4",
|
"typescript": "^4.4.4",
|
||||||
"unplugin-icons": "^0.12.17",
|
"unplugin-icons": "^0.12.18",
|
||||||
"unplugin-vue-components": "^0.17.0",
|
"unplugin-vue-components": "^0.17.0",
|
||||||
"vite": "2.5.10",
|
"vite": "~2.5.10",
|
||||||
"vite-plugin-html": "^2.1.1",
|
"vite-plugin-html": "^2.1.1",
|
||||||
"vite-plugin-windicss": "^1.4.12",
|
"vite-plugin-windicss": "^1.4.12",
|
||||||
"vue-tsc": "^0.28.10",
|
"vue-tsc": "^0.28.10",
|
||||||
"vueuc": "^0.4.15",
|
"vueuc": "^0.4.15",
|
||||||
"windicss": "^3.2.0"
|
"windicss": "^3.2.1"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"commitizen": {
|
"commitizen": {
|
||||||
|
1144
pnpm-lock.yaml
1144
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="absolute-lt w-full h-full overflow-hidden">
|
<div class="absolute-lt wh-full overflow-hidden">
|
||||||
<div class="absolute -right-300px -top-900px">
|
<div class="absolute -right-300px -top-900px">
|
||||||
<corner-top :start-color="firstColor" :end-color="secondColor" />
|
<corner-top :start-color="firstColor" :end-color="secondColor" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="scrollbar" class="w-full h-full text-left">
|
<div ref="scrollbar" class="wh-full text-left">
|
||||||
<div ref="scrollbarContent" class="inline-block" :class="{ 'h-full': !options.scrollY }">
|
<div ref="scrollbarContent" class="inline-block" :class="{ 'h-full': !options.scrollY }">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
@mouseenter="setTrue"
|
@mouseenter="setTrue"
|
||||||
@mouseleave="setFalse"
|
@mouseleave="setFalse"
|
||||||
>
|
>
|
||||||
<div class="absolute-lb w-full h-full overflow-hidden">
|
<div class="absolute-lb wh-full overflow-hidden">
|
||||||
<svg-radius-bg
|
<svg-radius-bg
|
||||||
class="w-full h-full"
|
class="wh-full"
|
||||||
:is-active="isActive"
|
:is-active="isActive"
|
||||||
:is-hover="isHover"
|
:is-hover="isHover"
|
||||||
:dark-mode="darkMode"
|
:dark-mode="darkMode"
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
export * from './business';
|
export * from './business';
|
||||||
export * from './theme';
|
export * from './theme';
|
||||||
export * from './common';
|
export * from './common';
|
||||||
|
export * from './package';
|
||||||
|
4
src/interface/package.ts
Normal file
4
src/interface/package.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export interface VersionInfo {
|
||||||
|
name: string;
|
||||||
|
version: string;
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<hover-container class="px-12px" :show-tooltip="false">
|
<hover-container class="px-12px" :show-tooltip="false">
|
||||||
<n-switch :value="theme.darkMode" @update:value="handleDarkMode">
|
<n-switch :value="theme.darkMode" size="large" @update:value="handleDarkMode">
|
||||||
<template #checked>
|
<template #checked>
|
||||||
<icon-mdi-white-balance-sunny class="text-14px g_text-primary" />
|
<icon-mdi-white-balance-sunny class="text-14px g_text-primary" />
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<n-scrollbar ref="scrollbar" class="h-full" :x-scrollable="true" :content-class="routeProps.fullPage ? 'h-full' : ''">
|
<n-scrollbar ref="scrollbar" class="h-full" :x-scrollable="true" :content-class="routeProps.fullPage ? 'h-full' : ''">
|
||||||
<div class="inline-block w-full h-full bg-[#F6F9F8]">
|
<div class="inline-block wh-full bg-[#F6F9F8]">
|
||||||
<router-view v-slot="{ Component, route: itemRoute }">
|
<router-view v-slot="{ Component, route: itemRoute }">
|
||||||
<transition :name="theme.pageStyle.animateType" mode="out-in" appear>
|
<transition :name="theme.pageStyle.animateType" mode="out-in" appear>
|
||||||
<keep-alive :include="cacheRoutes">
|
<keep-alive :include="cacheRoutes">
|
||||||
|
@ -11,7 +11,6 @@ const ROUTE_HOME: CustomRoute = {
|
|||||||
path: EnumRoutePath.dashboard_analysis,
|
path: EnumRoutePath.dashboard_analysis,
|
||||||
component: DashboardAnalysis,
|
component: DashboardAnalysis,
|
||||||
meta: {
|
meta: {
|
||||||
keepAlive: true,
|
|
||||||
requiresAuth: true,
|
requiresAuth: true,
|
||||||
title: EnumRouteTitle.dashboard_analysis
|
title: EnumRouteTitle.dashboard_analysis
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ const authStore = defineStore({
|
|||||||
token: '',
|
token: '',
|
||||||
userInfo: {
|
userInfo: {
|
||||||
userId: '',
|
userId: '',
|
||||||
userName: '',
|
userName: 'Soybean',
|
||||||
userPhone: ''
|
userPhone: ''
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -33,7 +33,6 @@ const authStore = defineStore({
|
|||||||
resetAuthState() {
|
resetAuthState() {
|
||||||
removeToken();
|
removeToken();
|
||||||
this.$reset();
|
this.$reset();
|
||||||
// window.location.reload();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -2,3 +2,4 @@ export * from './auth';
|
|||||||
export * from './common';
|
export * from './common';
|
||||||
export * from './storage';
|
export * from './storage';
|
||||||
export * from './router';
|
export * from './router';
|
||||||
|
export * from './package';
|
||||||
|
31
src/utils/package/index.ts
Normal file
31
src/utils/package/index.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import type { VersionInfo } from '@/interface';
|
||||||
|
import version from './version.json';
|
||||||
|
|
||||||
|
interface Version {
|
||||||
|
dependencies: {
|
||||||
|
[key: string]: string;
|
||||||
|
};
|
||||||
|
devDependencies: {
|
||||||
|
[key: string]: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PackageVersion {
|
||||||
|
dependencies: VersionInfo[];
|
||||||
|
devDependencies: VersionInfo[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const versionWithType = version as Version;
|
||||||
|
|
||||||
|
function transformVersionData(tuple: [string, string]): VersionInfo {
|
||||||
|
const [name, version] = tuple;
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
version
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const packageVersion: PackageVersion = {
|
||||||
|
dependencies: Object.entries(versionWithType.dependencies).map(item => transformVersionData(item)),
|
||||||
|
devDependencies: Object.entries(versionWithType.dependencies).map(item => transformVersionData(item))
|
||||||
|
};
|
65
src/utils/package/version.json
Normal file
65
src/utils/package/version.json
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"@antv/g2plot": "^2.3.39",
|
||||||
|
"@better-scroll/core": "^2.4.2",
|
||||||
|
"@vueuse/core": "^6.7.4",
|
||||||
|
"axios": "^0.24.0",
|
||||||
|
"chroma-js": "^2.1.2",
|
||||||
|
"clipboard": "^2.0.8",
|
||||||
|
"dayjs": "^1.10.7",
|
||||||
|
"form-data": "^4.0.0",
|
||||||
|
"naive-ui": "^2.20.1",
|
||||||
|
"pinia": "^2.0.0",
|
||||||
|
"qs": "^6.10.1",
|
||||||
|
"vue": "^3.2.20",
|
||||||
|
"vue-router": "^4.0.11"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@commitlint/cli": "^14.1.0",
|
||||||
|
"@commitlint/config-conventional": "^14.1.0",
|
||||||
|
"@iconify/json": "^1.1.417",
|
||||||
|
"@iconify/vue": "^3.0.0",
|
||||||
|
"@types/chroma-js": "^2.1.3",
|
||||||
|
"@types/qs": "^6.9.7",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.3.0",
|
||||||
|
"@typescript-eslint/parser": "^5.3.0",
|
||||||
|
"@vicons/antd": "^0.11.0",
|
||||||
|
"@vicons/carbon": "^0.11.0",
|
||||||
|
"@vicons/fa": "^0.11.0",
|
||||||
|
"@vicons/fluent": "^0.11.0",
|
||||||
|
"@vicons/ionicons4": "^0.11.0",
|
||||||
|
"@vicons/ionicons5": "^0.11.0",
|
||||||
|
"@vicons/material": "^0.11.0",
|
||||||
|
"@vicons/tabler": "^0.11.0",
|
||||||
|
"@vitejs/plugin-vue": "^1.9.4",
|
||||||
|
"@vue/compiler-sfc": "^3.2.21",
|
||||||
|
"@vue/eslint-config-prettier": "^6.0.0",
|
||||||
|
"@vue/eslint-config-typescript": "^9.0.0",
|
||||||
|
"commitizen": "^4.2.4",
|
||||||
|
"cz-conventional-changelog": "^3.3.0",
|
||||||
|
"cz-customizable": "^6.3.0",
|
||||||
|
"dotenv": "^10.0.0",
|
||||||
|
"eslint": "^8.1.0",
|
||||||
|
"eslint-config-airbnb-base": "^14.2.1",
|
||||||
|
"eslint-config-prettier": "^8.3.0",
|
||||||
|
"eslint-plugin-import": "^2.25.2",
|
||||||
|
"eslint-plugin-prettier": "^4.0.0",
|
||||||
|
"eslint-plugin-vue": "^8.0.3",
|
||||||
|
"husky": "^7.0.4",
|
||||||
|
"lint-staged": "^11.2.6",
|
||||||
|
"patch-package": "^6.4.7",
|
||||||
|
"postinstall-postinstall": "^2.1.0",
|
||||||
|
"prettier": "^2.4.1",
|
||||||
|
"rollup-plugin-visualizer": "^5.5.2",
|
||||||
|
"sass": "^1.43.4",
|
||||||
|
"typescript": "^4.4.4",
|
||||||
|
"unplugin-icons": "^0.12.17",
|
||||||
|
"unplugin-vue-components": "^0.17.0",
|
||||||
|
"vite": "2.5.10",
|
||||||
|
"vite-plugin-html": "^2.1.1",
|
||||||
|
"vite-plugin-windicss": "^1.4.12",
|
||||||
|
"vue-tsc": "^0.28.10",
|
||||||
|
"vueuc": "^0.4.15",
|
||||||
|
"windicss": "^3.2.0"
|
||||||
|
}
|
||||||
|
}
|
18
src/views/about/components/DevDependency/index.vue
Normal file
18
src/views/about/components/DevDependency/index.vue
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<template>
|
||||||
|
<shadow-card class="p-18px !rounded-4px">
|
||||||
|
<h3 class="pb-18px text-16px font-semibold">开发环境依赖</h3>
|
||||||
|
<n-descriptions label-placement="left" bordered size="small">
|
||||||
|
<n-descriptions-item v-for="item in dependencies" :key="item.name" :label="item.name">
|
||||||
|
{{ item.version }}
|
||||||
|
</n-descriptions-item>
|
||||||
|
</n-descriptions>
|
||||||
|
</shadow-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { NDescriptions, NDescriptionsItem } from 'naive-ui';
|
||||||
|
import { packageVersion } from '@/utils';
|
||||||
|
|
||||||
|
const dependencies = packageVersion.devDependencies;
|
||||||
|
</script>
|
||||||
|
<style scoped></style>
|
18
src/views/about/components/ProDependency/index.vue
Normal file
18
src/views/about/components/ProDependency/index.vue
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<template>
|
||||||
|
<shadow-card class="p-18px !rounded-4px">
|
||||||
|
<h3 class="pb-18px text-16px font-semibold">生产环境依赖</h3>
|
||||||
|
<n-descriptions label-placement="left" bordered size="small">
|
||||||
|
<n-descriptions-item v-for="item in dependencies" :key="item.name" :label="item.name">
|
||||||
|
{{ item.version }}
|
||||||
|
</n-descriptions-item>
|
||||||
|
</n-descriptions>
|
||||||
|
</shadow-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { NDescriptions, NDescriptionsItem } from 'naive-ui';
|
||||||
|
import { packageVersion } from '@/utils';
|
||||||
|
|
||||||
|
const { dependencies } = packageVersion;
|
||||||
|
</script>
|
||||||
|
<style scoped></style>
|
24
src/views/about/components/ProjectInfo/index.vue
Normal file
24
src/views/about/components/ProjectInfo/index.vue
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<template>
|
||||||
|
<shadow-card class="p-18px !rounded-4px">
|
||||||
|
<h3 class="pb-18px text-16px font-semibold">项目信息</h3>
|
||||||
|
<n-descriptions label-placement="left" bordered size="small" :column="2">
|
||||||
|
<n-descriptions-item label="版本">
|
||||||
|
<n-tag type="primary">1.0.0</n-tag>
|
||||||
|
</n-descriptions-item>
|
||||||
|
<n-descriptions-item label="最后编译时间">
|
||||||
|
<n-tag type="primary">2021-11-04</n-tag>
|
||||||
|
</n-descriptions-item>
|
||||||
|
<n-descriptions-item label="Github地址">
|
||||||
|
<a class="g_text-primary" href="https://github.com/honghuangdc/soybean-admin" target="_blank">Github地址</a>
|
||||||
|
</n-descriptions-item>
|
||||||
|
<n-descriptions-item label="预览地址">
|
||||||
|
<a class="g_text-primary" href="https://soybean.pro" target="_blank">预览地址</a>
|
||||||
|
</n-descriptions-item>
|
||||||
|
</n-descriptions>
|
||||||
|
</shadow-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { NDescriptions, NDescriptionsItem, NTag } from 'naive-ui';
|
||||||
|
</script>
|
||||||
|
<style scoped></style>
|
12
src/views/about/components/ProjectIntroduction/index.vue
Normal file
12
src/views/about/components/ProjectIntroduction/index.vue
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
<shadow-card class="h-120px p-18px !rounded-4px">
|
||||||
|
<h3 class="h-36px leading-36px text-26px font-bold">关于</h3>
|
||||||
|
<p class="leading-24px">
|
||||||
|
Soybean Admin 是一个基于 Vue3、Vite、Naive UI、TypeScript
|
||||||
|
的中后台解决方案,它使用了最新的前端技术栈,并提炼了典型的业务模型,页面,包括二次封装组件、动态菜单、权限校验、粒子化权限控制等功能,它可以帮助你快速搭建企业级中后台项目,相信不管是从新技术使用还是其他方面,都能帮助到你。
|
||||||
|
</p>
|
||||||
|
</shadow-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts"></script>
|
||||||
|
<style scoped></style>
|
6
src/views/about/components/index.ts
Normal file
6
src/views/about/components/index.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import ProjectIntroduction from './ProjectIntroduction/index.vue';
|
||||||
|
import ProjectInfo from './ProjectInfo/index.vue';
|
||||||
|
import ProDependency from './ProDependency/index.vue';
|
||||||
|
import DevDependency from './DevDependency/index.vue';
|
||||||
|
|
||||||
|
export { ProjectIntroduction, ProjectInfo, ProDependency, DevDependency };
|
@ -1,6 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>关于</div>
|
<n-space :vertical="true" :size="16">
|
||||||
|
<project-introduction />
|
||||||
|
<project-info />
|
||||||
|
<pro-dependency />
|
||||||
|
<dev-dependency />
|
||||||
|
</n-space>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts"></script>
|
<script setup lang="ts">
|
||||||
|
import { NSpace } from 'naive-ui';
|
||||||
|
import { ProjectIntroduction, ProjectInfo, ProDependency, DevDependency } from './components';
|
||||||
|
</script>
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
134
src/views/dashboard/analysis/components/BottomPart/index.vue
Normal file
134
src/views/dashboard/analysis/components/BottomPart/index.vue
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
<template>
|
||||||
|
<n-grid :x-gap="16" :y-gap="16" :item-responsive="true" responsive="screen">
|
||||||
|
<n-grid-item span="s:24 m:8">
|
||||||
|
<shadow-card class="h-400px p-18px">
|
||||||
|
<n-timeline>
|
||||||
|
<n-timeline-item v-for="item in timelines" :key="item.type" v-bind="item" />
|
||||||
|
</n-timeline>
|
||||||
|
</shadow-card>
|
||||||
|
</n-grid-item>
|
||||||
|
<n-grid-item span="s:24 m:16">
|
||||||
|
<shadow-card class="h-400px p-18px">
|
||||||
|
<n-data-table size="small" :columns="columns" :data="tableData" />
|
||||||
|
</shadow-card>
|
||||||
|
</n-grid-item>
|
||||||
|
</n-grid>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { h } from 'vue';
|
||||||
|
import { NGrid, NGridItem, NTimeline, NTimelineItem, NDataTable, NTag } from 'naive-ui';
|
||||||
|
import { ShadowCard } from '@/components';
|
||||||
|
|
||||||
|
interface TimelineData {
|
||||||
|
type: 'default' | 'info' | 'success' | 'warning' | 'error';
|
||||||
|
title: string;
|
||||||
|
content: string;
|
||||||
|
time: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TableData {
|
||||||
|
key: number;
|
||||||
|
name: string;
|
||||||
|
age: number;
|
||||||
|
address: string;
|
||||||
|
tags: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const timelines: TimelineData[] = [
|
||||||
|
{ type: 'default', title: '啊', content: '', time: '2021-10-10 20:46' },
|
||||||
|
{ type: 'success', title: '成功', content: '哪里成功', time: '2021-10-10 20:46' },
|
||||||
|
{ type: 'error', title: '错误', content: '哪里错误', time: '2021-10-10 20:46' },
|
||||||
|
{ type: 'warning', title: '警告', content: '哪里警告', time: '2021-10-10 20:46' },
|
||||||
|
{ type: 'info', title: '信息', content: '是的', time: '2021-10-10 20:46' }
|
||||||
|
];
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: 'Name',
|
||||||
|
key: 'name'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Age',
|
||||||
|
key: 'age'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Address',
|
||||||
|
key: 'address'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Tags',
|
||||||
|
key: 'tags',
|
||||||
|
render(row: TableData) {
|
||||||
|
const tags = row.tags.map(tagKey => {
|
||||||
|
return h(
|
||||||
|
NTag,
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
marginRight: '6px'
|
||||||
|
},
|
||||||
|
type: 'info'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
default: () => tagKey
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const tableData: TableData[] = [
|
||||||
|
{
|
||||||
|
key: 0,
|
||||||
|
name: 'John Brown',
|
||||||
|
age: 32,
|
||||||
|
address: 'New York No. 1 Lake Park',
|
||||||
|
tags: ['nice', 'developer']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 1,
|
||||||
|
name: 'Jim Green',
|
||||||
|
age: 42,
|
||||||
|
address: 'London No. 1 Lake Park',
|
||||||
|
tags: ['wow']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 2,
|
||||||
|
name: 'Joe Black',
|
||||||
|
age: 32,
|
||||||
|
address: 'Sidney No. 1 Lake Park',
|
||||||
|
tags: ['cool', 'teacher']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 3,
|
||||||
|
name: 'Soybean',
|
||||||
|
age: 25,
|
||||||
|
address: 'China Shenzhen',
|
||||||
|
tags: ['handsome', 'peogrammer']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 4,
|
||||||
|
name: 'John Brown',
|
||||||
|
age: 32,
|
||||||
|
address: 'New York No. 1 Lake Park',
|
||||||
|
tags: ['nice', 'developer']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 5,
|
||||||
|
name: 'Jim Green',
|
||||||
|
age: 42,
|
||||||
|
address: 'London No. 1 Lake Park',
|
||||||
|
tags: ['wow']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 6,
|
||||||
|
name: 'Joe Black',
|
||||||
|
age: 32,
|
||||||
|
address: 'Sidney No. 1 Lake Park',
|
||||||
|
tags: ['cool', 'teacher']
|
||||||
|
}
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
<style scoped></style>
|
@ -1,74 +0,0 @@
|
|||||||
<template>
|
|
||||||
<n-grid cols="1 s:2 m:3 l:4 xl:4 2xl:4" responsive="screen" :x-gap="12" :y-gap="8">
|
|
||||||
<n-grid-item v-for="item in cardData" :key="item.title">
|
|
||||||
<n-card :title="item.title" :segmented="{ content: true, footer: true }" size="small" :bordered="false">
|
|
||||||
<template #header-extra>
|
|
||||||
<n-tag :type="item.color">{{ item.action }}</n-tag>
|
|
||||||
</template>
|
|
||||||
<div class="flex justify-between py-4px px-4px">
|
|
||||||
<n-skeleton v-if="loading" :width="100" size="medium" />
|
|
||||||
<count-to v-else prefix="$" :start-value="1" :end-value="item.value" class="text-30px text-[#666]" />
|
|
||||||
</div>
|
|
||||||
<div class="flex justify-between p-8px px-16px">
|
|
||||||
<n-skeleton v-if="loading" :width="100" size="medium" />
|
|
||||||
<template v-else>
|
|
||||||
<span>总{{ item.title }}</span>
|
|
||||||
<count-to prefix="$" :start-value="1" :end-value="item.total" />
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</n-card>
|
|
||||||
</n-grid-item>
|
|
||||||
</n-grid>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { NGrid, NGridItem, NCard, NTag, NSkeleton } from 'naive-ui';
|
|
||||||
import { CountTo } from '@/components';
|
|
||||||
|
|
||||||
interface CardData {
|
|
||||||
title: string;
|
|
||||||
value: number;
|
|
||||||
total: number;
|
|
||||||
color: 'default' | 'primary' | 'warning' | 'success' | 'info' | 'error';
|
|
||||||
action: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
defineProps({
|
|
||||||
loading: {
|
|
||||||
type: Boolean,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const cardData: CardData[] = [
|
|
||||||
{
|
|
||||||
title: '访问数',
|
|
||||||
value: 2000,
|
|
||||||
total: 120000,
|
|
||||||
color: 'error',
|
|
||||||
action: '月'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '成交额',
|
|
||||||
value: 20000,
|
|
||||||
total: 500000,
|
|
||||||
color: 'success',
|
|
||||||
action: '月'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '下载数',
|
|
||||||
value: 8000,
|
|
||||||
total: 120000,
|
|
||||||
color: 'primary',
|
|
||||||
action: '周'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '成交数',
|
|
||||||
value: 5000,
|
|
||||||
total: 50000,
|
|
||||||
color: 'warning',
|
|
||||||
action: '年'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
</script>
|
|
||||||
<style scoped></style>
|
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bg-gradient w-full h-full p-16px text-white">
|
<div class="bg-gradient wh-full p-16px text-white">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
@ -0,0 +1,3 @@
|
|||||||
|
import GradientBg from './GradientBg.vue';
|
||||||
|
|
||||||
|
export { GradientBg };
|
75
src/views/dashboard/analysis/components/DataCard/index.vue
Normal file
75
src/views/dashboard/analysis/components/DataCard/index.vue
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<template>
|
||||||
|
<n-grid cols="s:1 m:2 l:4" responsive="screen" :x-gap="16" :y-gap="16">
|
||||||
|
<n-grid-item v-for="item in cardData" :key="item.id">
|
||||||
|
<shadow-card class="h-100px">
|
||||||
|
<gradient-bg :start-color="item.colors[0]" :end-color="item.colors[1]">
|
||||||
|
<h3 class="text-16px">{{ item.title }}</h3>
|
||||||
|
<div class="flex justify-between pt-12px">
|
||||||
|
<component :is="item.icon" class="text-32px" />
|
||||||
|
<count-to
|
||||||
|
:prefix="item.unit"
|
||||||
|
:start-value="1"
|
||||||
|
:end-value="item.value"
|
||||||
|
class="text-30px text-white dark:text-dark"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</gradient-bg>
|
||||||
|
</shadow-card>
|
||||||
|
</n-grid-item>
|
||||||
|
</n-grid>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { VNodeChild } from 'vue';
|
||||||
|
import { NGrid, NGridItem } from 'naive-ui';
|
||||||
|
import { BarChartOutlined, MoneyCollectOutlined, TrademarkOutlined } from '@vicons/antd';
|
||||||
|
import { DocumentDownload } from '@vicons/carbon';
|
||||||
|
import { ShadowCard, CountTo } from '@/components';
|
||||||
|
import { dynamicIconRender } from '@/utils';
|
||||||
|
import { GradientBg } from './components';
|
||||||
|
|
||||||
|
interface CardData {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
value: number;
|
||||||
|
unit: string;
|
||||||
|
colors: [string, string];
|
||||||
|
icon: () => VNodeChild;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cardData: CardData[] = [
|
||||||
|
{
|
||||||
|
id: 'visit',
|
||||||
|
title: '访问量',
|
||||||
|
value: 1000000,
|
||||||
|
unit: '',
|
||||||
|
colors: ['#ec4786', '#b955a4'],
|
||||||
|
icon: dynamicIconRender(BarChartOutlined)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'amount',
|
||||||
|
title: '成交额',
|
||||||
|
value: 234567.89,
|
||||||
|
unit: '$',
|
||||||
|
colors: ['#865ec0', '#5144b4'],
|
||||||
|
icon: dynamicIconRender(MoneyCollectOutlined)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'download',
|
||||||
|
title: '下载数',
|
||||||
|
value: 666666,
|
||||||
|
unit: '',
|
||||||
|
colors: ['#56cdf3', '#719de3'],
|
||||||
|
icon: dynamicIconRender(DocumentDownload)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'trade',
|
||||||
|
title: '成交数',
|
||||||
|
value: 999999,
|
||||||
|
unit: '',
|
||||||
|
colors: ['#fcbc25', '#f68057'],
|
||||||
|
icon: dynamicIconRender(TrademarkOutlined)
|
||||||
|
}
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
<style scoped></style>
|
@ -1,87 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="py-16px">
|
|
||||||
<n-grid cols="1 s:2 m:3 l:8 xl:8 2xl:8" responsive="screen" :x-gap="16" :y-gap="8">
|
|
||||||
<n-grid-item v-for="item in navData" :key="item.label">
|
|
||||||
<n-card content-style="padding-top: 0;" size="small" :bordered="false">
|
|
||||||
<template #footer>
|
|
||||||
<n-skeleton v-if="loading" size="medium" />
|
|
||||||
<div v-else class="cursor-pointer">
|
|
||||||
<p class="flex-x-center">
|
|
||||||
<span>
|
|
||||||
<n-icon :size="32" class="flex-1" :color="item.color">
|
|
||||||
<Icon :icon="item.icon" />
|
|
||||||
</n-icon>
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<p class="flex-x-center">
|
|
||||||
<span>{{ item.label }}</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</n-card>
|
|
||||||
</n-grid-item>
|
|
||||||
</n-grid>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { NGrid, NGridItem, NCard, NSkeleton, NIcon } from 'naive-ui';
|
|
||||||
import { Icon } from '@iconify/vue';
|
|
||||||
|
|
||||||
interface NavData {
|
|
||||||
label: string;
|
|
||||||
color: string;
|
|
||||||
icon: String;
|
|
||||||
}
|
|
||||||
|
|
||||||
defineProps({
|
|
||||||
loading: {
|
|
||||||
type: Boolean,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const navData: NavData[] = [
|
|
||||||
{
|
|
||||||
label: '用户',
|
|
||||||
color: '#69c0ff',
|
|
||||||
icon: 'ant-design:usergroup-add-outlined'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '分析',
|
|
||||||
color: '#69c0ff',
|
|
||||||
icon: 'ant-design:bar-chart-outlined'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '商品',
|
|
||||||
color: '#ff9c6e',
|
|
||||||
icon: 'ant-design:shopping-cart-outlined'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '订单',
|
|
||||||
color: '#b37feb',
|
|
||||||
icon: 'ant-design:account-book-outlined'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '票据',
|
|
||||||
color: '#ffd666',
|
|
||||||
icon: 'ant-design:credit-card-outlined'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '消息',
|
|
||||||
color: '#5cdbd3',
|
|
||||||
icon: 'ant-design:mail-outlined'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '标签',
|
|
||||||
color: '#ff85c0',
|
|
||||||
icon: 'ant-design:tags-outlined'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '配置',
|
|
||||||
color: '#ffc069',
|
|
||||||
icon: 'ant-design:setting-outlined'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
</script>
|
|
||||||
<style scoped></style>
|
|
152
src/views/dashboard/analysis/components/TopChart/data.json
Normal file
152
src/views/dashboard/analysis/components/TopChart/data.json
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"date": "2021/10/1",
|
||||||
|
"type": "下载量",
|
||||||
|
"value": 4623
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/1",
|
||||||
|
"type": "注册数",
|
||||||
|
"value": 2208
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/2",
|
||||||
|
"type": "下载量",
|
||||||
|
"value": 6145
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/2",
|
||||||
|
"type": "注册数",
|
||||||
|
"value": 2016
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/3",
|
||||||
|
"type": "下载量",
|
||||||
|
"value": 508
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/3",
|
||||||
|
"type": "注册数",
|
||||||
|
"value": 2916
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/4",
|
||||||
|
"type": "下载量",
|
||||||
|
"value": 6268
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/4",
|
||||||
|
"type": "注册数",
|
||||||
|
"value": 4512
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/5",
|
||||||
|
"type": "下载量",
|
||||||
|
"value": 6411
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/5",
|
||||||
|
"type": "注册数",
|
||||||
|
"value": 8281
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/6",
|
||||||
|
"type": "下载量",
|
||||||
|
"value": 1890
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/6",
|
||||||
|
"type": "注册数",
|
||||||
|
"value": 2008
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/7",
|
||||||
|
"type": "下载量",
|
||||||
|
"value": 4251
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/7",
|
||||||
|
"type": "注册数",
|
||||||
|
"value": 1963
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/8",
|
||||||
|
"type": "下载量",
|
||||||
|
"value": 2978
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/8",
|
||||||
|
"type": "注册数",
|
||||||
|
"value": 2367
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/9",
|
||||||
|
"type": "下载量",
|
||||||
|
"value": 3880
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/9",
|
||||||
|
"type": "注册数",
|
||||||
|
"value": 2956
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/10",
|
||||||
|
"type": "下载量",
|
||||||
|
"value": 3606
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/10",
|
||||||
|
"type": "注册数",
|
||||||
|
"value": 678
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/11",
|
||||||
|
"type": "下载量",
|
||||||
|
"value": 4311
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/11",
|
||||||
|
"type": "注册数",
|
||||||
|
"value": 3188
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/12",
|
||||||
|
"type": "下载量",
|
||||||
|
"value": 4116
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/12",
|
||||||
|
"type": "注册数",
|
||||||
|
"value": 3491
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/13",
|
||||||
|
"type": "下载量",
|
||||||
|
"value": 6419
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/13",
|
||||||
|
"type": "注册数",
|
||||||
|
"value": 2852
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/14",
|
||||||
|
"type": "下载量",
|
||||||
|
"value": 1643
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/14",
|
||||||
|
"type": "注册数",
|
||||||
|
"value": 4788
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/15",
|
||||||
|
"type": "下载量",
|
||||||
|
"value": 445
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2021/10/15",
|
||||||
|
"type": "注册数",
|
||||||
|
"value": 4319
|
||||||
|
}
|
||||||
|
]
|
127
src/views/dashboard/analysis/components/TopChart/index.vue
Normal file
127
src/views/dashboard/analysis/components/TopChart/index.vue
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
<template>
|
||||||
|
<n-grid :x-gap="16" :y-gap="16" :item-responsive="true" responsive="screen">
|
||||||
|
<n-grid-item span="s:24 m:16">
|
||||||
|
<shadow-card class="flex h-360px p-18px">
|
||||||
|
<div class="w-200px h-full py-12px">
|
||||||
|
<h3 class="text-16px font-bold">Dashboard</h3>
|
||||||
|
<p class="text-[#aaa]">Overview Of Lasted Month</p>
|
||||||
|
<h3 class="pt-36px text-24px font-bold">
|
||||||
|
<count-to prefix="$" :start-value="0" :end-value="7754" />
|
||||||
|
</h3>
|
||||||
|
<p class="text-[#aaa]">Current Month Earnings</p>
|
||||||
|
<h3 class="pt-36px text-24px font-bold">
|
||||||
|
<count-to :start-value="0" :end-value="1234" />
|
||||||
|
</h3>
|
||||||
|
<p class="text-[#aaa]">Current Month Sales</p>
|
||||||
|
<n-button class="mt-24px" type="primary">Last Month Summary</n-button>
|
||||||
|
</div>
|
||||||
|
<div ref="lineRef" class="flex-1 h-full"></div>
|
||||||
|
</shadow-card>
|
||||||
|
</n-grid-item>
|
||||||
|
<n-grid-item span="s:24 m:8">
|
||||||
|
<shadow-card class="h-360px">
|
||||||
|
<div ref="pieRef" class="wh-full"></div>
|
||||||
|
</shadow-card>
|
||||||
|
</n-grid-item>
|
||||||
|
</n-grid>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted } from 'vue';
|
||||||
|
import { NGrid, NGridItem, NButton } from 'naive-ui';
|
||||||
|
import { Line, Pie } from '@antv/g2plot';
|
||||||
|
import { ShadowCard, CountTo } from '@/components';
|
||||||
|
import data from './data.json';
|
||||||
|
|
||||||
|
const lineRef = ref<HTMLElement | null>(null);
|
||||||
|
const line = ref<Line | null>(null);
|
||||||
|
const pieRef = ref<HTMLElement | null>(null);
|
||||||
|
const pie = ref<Pie | null>(null);
|
||||||
|
|
||||||
|
function renderLineChart() {
|
||||||
|
line.value = new Line(lineRef.value!, {
|
||||||
|
data,
|
||||||
|
autoFit: true,
|
||||||
|
xField: 'date',
|
||||||
|
yField: 'value',
|
||||||
|
seriesField: 'type',
|
||||||
|
lineStyle: {
|
||||||
|
lineWidth: 4
|
||||||
|
},
|
||||||
|
area: {
|
||||||
|
style: {
|
||||||
|
fill: 'l(270) 0:#ffffff 0.5:#7ec2f3 1:#1890ff'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
smooth: true,
|
||||||
|
animation: {
|
||||||
|
appear: {
|
||||||
|
animation: 'wave-in',
|
||||||
|
duration: 2000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
line.value.render();
|
||||||
|
}
|
||||||
|
function renderPieChart() {
|
||||||
|
const data = [
|
||||||
|
{ type: '学习', value: 20 },
|
||||||
|
{ type: '娱乐', value: 10 },
|
||||||
|
{ type: '工作', value: 30 },
|
||||||
|
{ type: '休息', value: 40 }
|
||||||
|
];
|
||||||
|
pie.value = new Pie(pieRef.value!, {
|
||||||
|
appendPadding: 10,
|
||||||
|
data,
|
||||||
|
angleField: 'value',
|
||||||
|
colorField: 'type',
|
||||||
|
radius: 0.8,
|
||||||
|
innerRadius: 0.65,
|
||||||
|
meta: {
|
||||||
|
value: {
|
||||||
|
formatter: v => `${v}%`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
type: 'spider',
|
||||||
|
offset: '8%',
|
||||||
|
autoRotate: false,
|
||||||
|
formatter: ({ percent }) => `${(percent * 100).toFixed(0)}%`,
|
||||||
|
style: { fontSize: 18 }
|
||||||
|
},
|
||||||
|
statistic: undefined,
|
||||||
|
pieStyle: {
|
||||||
|
radius: [20]
|
||||||
|
},
|
||||||
|
color: ['#025DF4', '#DB6BCF', '#2498D1', '#FF745A', '#007E99', '#FFA8A8', '#2391FF'],
|
||||||
|
legend: {
|
||||||
|
position: 'bottom'
|
||||||
|
},
|
||||||
|
interactions: [
|
||||||
|
{ type: 'element-selected' },
|
||||||
|
{ type: 'element-active' },
|
||||||
|
{
|
||||||
|
type: 'pie-statistic-active',
|
||||||
|
cfg: {
|
||||||
|
start: [
|
||||||
|
{ trigger: 'element:mouseenter', action: 'pie-statistic:change' },
|
||||||
|
{ trigger: 'legend-item:mouseenter', action: 'pie-statistic:change' }
|
||||||
|
],
|
||||||
|
end: [
|
||||||
|
{ trigger: 'element:mouseleave', action: 'pie-statistic:reset' },
|
||||||
|
{ trigger: 'legend-item:mouseleave', action: 'pie-statistic:reset' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
pie.value.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
renderLineChart();
|
||||||
|
renderPieChart();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style scoped></style>
|
@ -1,4 +1,5 @@
|
|||||||
import DataCard from './DataCard.vue';
|
import TopChart from './TopChart/index.vue';
|
||||||
import NavCard from './NavCard.vue';
|
import DataCard from './DataCard/index.vue';
|
||||||
|
import BottomPart from './BottomPart/index.vue';
|
||||||
|
|
||||||
export { DataCard, NavCard };
|
export { TopChart, DataCard, BottomPart };
|
||||||
|
@ -1,24 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<n-space :vertical="true" :size="16">
|
||||||
<data-card :loading="loading" />
|
<top-chart />
|
||||||
<nav-card :loading="loading" />
|
<data-card />
|
||||||
</div>
|
<bottom-part />
|
||||||
|
</n-space>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onActivated } from 'vue';
|
import { NSpace } from 'naive-ui';
|
||||||
import { useLoading } from '@/hooks';
|
import { TopChart, DataCard, BottomPart } from './components';
|
||||||
import { DataCard, NavCard } from './components';
|
|
||||||
|
|
||||||
const { loading, startLoading, endLoading } = useLoading(true);
|
|
||||||
|
|
||||||
function handleEndLoading() {
|
|
||||||
startLoading();
|
|
||||||
setTimeout(() => {
|
|
||||||
endLoading();
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
onActivated(() => {
|
|
||||||
handleEndLoading();
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
<template>
|
||||||
|
<shadow-card class="flex-y-center justify-between h-120px p-12px">
|
||||||
|
<div class="flex-y-center">
|
||||||
|
<img src="@/assets/svg/avatar/avatar01.svg" alt="" class="w-70px h-70px" />
|
||||||
|
<div class="pl-12px">
|
||||||
|
<h3 class="text-18px font-semibold">早安,{{ auth.userInfo.userName }}, 今天又是充满活力的一天!</h3>
|
||||||
|
<p class="leading-30px text-[#999]">今日多云转晴,20℃ - 25℃!</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<n-space :size="36">
|
||||||
|
<n-statistic v-for="item in statisticData" :key="item.id" v-bind="item"></n-statistic>
|
||||||
|
</n-space>
|
||||||
|
</shadow-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { NSpace, NStatistic } from 'naive-ui';
|
||||||
|
import { useAuthStore } from '@/store';
|
||||||
|
import { ShadowCard } from '@/components';
|
||||||
|
|
||||||
|
interface StatisticData {
|
||||||
|
id: number;
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auth = useAuthStore();
|
||||||
|
|
||||||
|
const statisticData: StatisticData[] = [
|
||||||
|
{
|
||||||
|
id: 0,
|
||||||
|
label: '经验',
|
||||||
|
value: '3年'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
label: '项目数量',
|
||||||
|
value: '10+'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
label: '主要技术栈',
|
||||||
|
value: 'TS,Vue3,React,Nodejs'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
<style scoped></style>
|
@ -1,3 +1,3 @@
|
|||||||
import GradientBg from './GradientBg.vue';
|
import HeaderInfo from './HeaderInfo/index.vue';
|
||||||
|
|
||||||
export { GradientBg };
|
export { HeaderInfo };
|
||||||
|
@ -1,93 +1,25 @@
|
|||||||
<template>
|
<template>
|
||||||
<n-space :vertical="true" :size="16">
|
<n-space :vertical="true" :size="16">
|
||||||
<n-grid :x-gap="16" :y-gap="16" :item-responsive="true" responsive="screen">
|
<header-info />
|
||||||
<n-grid-item span="s:24 m:16">
|
|
||||||
<shadow-card class="h-360px"></shadow-card>
|
|
||||||
</n-grid-item>
|
|
||||||
<n-grid-item span="s:24 m:8">
|
|
||||||
<shadow-card class="h-360px"></shadow-card>
|
|
||||||
</n-grid-item>
|
|
||||||
</n-grid>
|
|
||||||
<n-grid cols="s:1 m:2 l:4" responsive="screen" :x-gap="16" :y-gap="16">
|
|
||||||
<n-grid-item v-for="item in cardData" :key="item.id">
|
|
||||||
<shadow-card class="h-100px">
|
|
||||||
<gradient-bg :start-color="item.colors[0]" :end-color="item.colors[1]">
|
|
||||||
<h3 class="text-16px">{{ item.title }}</h3>
|
|
||||||
<div class="flex justify-between pt-12px">
|
|
||||||
<component :is="item.icon" class="text-32px" />
|
|
||||||
<count-to
|
|
||||||
:prefix="item.unit"
|
|
||||||
:start-value="1"
|
|
||||||
:end-value="item.value"
|
|
||||||
class="text-30px text-white dark:text-dark"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</gradient-bg>
|
|
||||||
</shadow-card>
|
|
||||||
</n-grid-item>
|
|
||||||
</n-grid>
|
|
||||||
<n-grid :x-gap="16" :y-gap="16" :item-responsive="true" responsive="screen">
|
|
||||||
<n-grid-item span="s:24 m:8">
|
|
||||||
<shadow-card class="h-360px"></shadow-card>
|
|
||||||
</n-grid-item>
|
|
||||||
<n-grid-item span="s:24 m:16">
|
|
||||||
<shadow-card class="h-360px"></shadow-card>
|
|
||||||
</n-grid-item>
|
|
||||||
</n-grid>
|
|
||||||
</n-space>
|
</n-space>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { VNodeChild } from 'vue';
|
import { onActivated } from 'vue';
|
||||||
import { NSpace, NGrid, NGridItem } from 'naive-ui';
|
import { NSpace } from 'naive-ui';
|
||||||
import { BarChartOutlined, MoneyCollectOutlined, TrademarkOutlined } from '@vicons/antd';
|
import { useLoading } from '@/hooks';
|
||||||
import { DocumentDownload } from '@vicons/carbon';
|
import { HeaderInfo } from './components';
|
||||||
import { ShadowCard, CountTo } from '@/components';
|
|
||||||
import { dynamicIconRender } from '@/utils';
|
|
||||||
import { GradientBg } from './components';
|
|
||||||
|
|
||||||
interface CardData {
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
id: string;
|
const { loading, startLoading, endLoading } = useLoading(true);
|
||||||
title: string;
|
|
||||||
value: number;
|
function handleEndLoading() {
|
||||||
unit: string;
|
startLoading();
|
||||||
colors: [string, string];
|
setTimeout(() => {
|
||||||
icon: () => VNodeChild;
|
endLoading();
|
||||||
|
}, 800);
|
||||||
}
|
}
|
||||||
|
onActivated(() => {
|
||||||
const cardData: CardData[] = [
|
handleEndLoading();
|
||||||
{
|
});
|
||||||
id: 'visit',
|
|
||||||
title: '访问量',
|
|
||||||
value: 1000000,
|
|
||||||
unit: '',
|
|
||||||
colors: ['#ec4786', '#b955a4'],
|
|
||||||
icon: dynamicIconRender(BarChartOutlined)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'amount',
|
|
||||||
title: '成交额',
|
|
||||||
value: 234567.89,
|
|
||||||
unit: '$',
|
|
||||||
colors: ['#865ec0', '#5144b4'],
|
|
||||||
icon: dynamicIconRender(MoneyCollectOutlined)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'download',
|
|
||||||
title: '下载数',
|
|
||||||
value: 666666,
|
|
||||||
unit: '',
|
|
||||||
colors: ['#56cdf3', '#719de3'],
|
|
||||||
icon: dynamicIconRender(DocumentDownload)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'trade',
|
|
||||||
title: '成交数',
|
|
||||||
value: 999999,
|
|
||||||
unit: '',
|
|
||||||
colors: ['#fcbc25', '#f68057'],
|
|
||||||
icon: dynamicIconRender(TrademarkOutlined)
|
|
||||||
}
|
|
||||||
];
|
|
||||||
</script>
|
</script>
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<iframe class="w-full h-full" :src="src"></iframe>
|
<iframe class="wh-full" :src="src"></iframe>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<iframe class="w-full h-full" :src="src"></iframe>
|
<iframe class="wh-full" :src="src"></iframe>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<iframe class="w-full h-full" :src="src"></iframe>
|
<iframe class="wh-full" :src="src"></iframe>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex-center flex-col w-full h-full">
|
<div class="flex-center flex-col wh-full">
|
||||||
<exception-svg type="403" :color="theme.themeColor" />
|
<exception-svg type="403" :color="theme.themeColor" />
|
||||||
<router-link to="/">
|
<router-link to="/">
|
||||||
<n-button type="primary">回到首页</n-button>
|
<n-button type="primary">回到首页</n-button>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex-center flex-col w-full h-full">
|
<div class="flex-center flex-col wh-full">
|
||||||
<exception-svg type="404" :color="theme.themeColor" />
|
<exception-svg type="404" :color="theme.themeColor" />
|
||||||
<router-link to="/">
|
<router-link to="/">
|
||||||
<n-button type="primary">回到首页</n-button>
|
<n-button type="primary">回到首页</n-button>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex-center flex-col w-full h-full">
|
<div class="flex-center flex-col wh-full">
|
||||||
<exception-svg type="500" :color="theme.themeColor" />
|
<exception-svg type="500" :color="theme.themeColor" />
|
||||||
<router-link to="/">
|
<router-link to="/">
|
||||||
<n-button type="primary">回到首页</n-button>
|
<n-button type="primary">回到首页</n-button>
|
||||||
|
@ -35,18 +35,20 @@ import { reactive, ref } from 'vue';
|
|||||||
import { NForm, NFormItem, NInput, NSpace, NCheckbox, NButton, useNotification } from 'naive-ui';
|
import { NForm, NFormItem, NInput, NSpace, NCheckbox, NButton, useNotification } from 'naive-ui';
|
||||||
import type { FormInst, FormRules } from 'naive-ui';
|
import type { FormInst, FormRules } from 'naive-ui';
|
||||||
import { EnumLoginModule } from '@/enum';
|
import { EnumLoginModule } from '@/enum';
|
||||||
|
import { useAuthStore } from '@/store';
|
||||||
import { useRouterChange, useRouteQuery, useLoading } from '@/hooks';
|
import { useRouterChange, useRouteQuery, useLoading } from '@/hooks';
|
||||||
import { setToken } from '@/utils';
|
import { setToken } from '@/utils';
|
||||||
import { OtherLogin } from './components';
|
import { OtherLogin } from './components';
|
||||||
|
|
||||||
|
const notification = useNotification();
|
||||||
|
const auth = useAuthStore();
|
||||||
const { toHome, toCurrentLogin, toLoginRedirectUrl } = useRouterChange();
|
const { toHome, toCurrentLogin, toLoginRedirectUrl } = useRouterChange();
|
||||||
const { loginRedirectUrl } = useRouteQuery();
|
const { loginRedirectUrl } = useRouteQuery();
|
||||||
const { loading, startLoading, endLoading } = useLoading();
|
const { loading, startLoading, endLoading } = useLoading();
|
||||||
const notification = useNotification();
|
|
||||||
|
|
||||||
const formRef = ref<(HTMLElement & FormInst) | null>(null);
|
const formRef = ref<(HTMLElement & FormInst) | null>(null);
|
||||||
const model = reactive({
|
const model = reactive({
|
||||||
phone: '15100000000',
|
phone: '151****3876',
|
||||||
pwd: '123456'
|
pwd: '123456'
|
||||||
});
|
});
|
||||||
const rules: FormRules = {
|
const rules: FormRules = {
|
||||||
@ -78,9 +80,10 @@ function handleSubmit(e: MouseEvent) {
|
|||||||
} else {
|
} else {
|
||||||
toHome();
|
toHome();
|
||||||
}
|
}
|
||||||
|
const { userName } = auth.userInfo;
|
||||||
notification.success({
|
notification.success({
|
||||||
title: '登录成功!',
|
title: '登录成功!',
|
||||||
content: '欢迎回来,Soybean!',
|
content: `欢迎回来,${userName}!`,
|
||||||
duration: 3000
|
duration: 3000
|
||||||
});
|
});
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="login-bg relative flex-center w-full h-full">
|
<div class="login-bg relative flex-center wh-full">
|
||||||
<shadow-card class="w-400px p-40px !rounded-20px z-10">
|
<shadow-card class="w-400px p-40px !rounded-20px z-10">
|
||||||
<header class="flex-y-center justify-between">
|
<header class="flex-y-center justify-between">
|
||||||
<div class="w-70px h-70px rounded-35px overflow-hidden">
|
<div class="w-70px h-70px rounded-35px overflow-hidden">
|
||||||
<system-logo class="w-full h-full" :fill="true" :color="theme.themeColor" />
|
<system-logo class="wh-full" :fill="true" :color="theme.themeColor" />
|
||||||
</div>
|
</div>
|
||||||
<n-gradient-text type="primary" :size="28">{{ title }}</n-gradient-text>
|
<n-gradient-text type="primary" :size="28">{{ title }}</n-gradient-text>
|
||||||
</header>
|
</header>
|
||||||
|
@ -12,6 +12,7 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
darkMode: 'class',
|
darkMode: 'class',
|
||||||
shortcuts: {
|
shortcuts: {
|
||||||
|
'wh-full': 'w-full h-full',
|
||||||
'center-layout': 'w-1280px mx-auto px-15px',
|
'center-layout': 'w-1280px mx-auto px-15px',
|
||||||
'flex-center': 'flex justify-center items-center',
|
'flex-center': 'flex justify-center items-center',
|
||||||
'flex-x-center': 'flex justify-center',
|
'flex-x-center': 'flex justify-center',
|
||||||
@ -22,12 +23,12 @@ export default defineConfig({
|
|||||||
'flex-1-hidden': 'flex-1 overflow-hidden',
|
'flex-1-hidden': 'flex-1 overflow-hidden',
|
||||||
'flex-col-stretch': 'flex flex-col items-stretch',
|
'flex-col-stretch': 'flex flex-col items-stretch',
|
||||||
'inline-flex-col-stretch': 'flex flex-col items-stretch',
|
'inline-flex-col-stretch': 'flex flex-col items-stretch',
|
||||||
'absolute-center': 'absolute left-0 top-0 flex justify-center items-center w-full h-full',
|
'absolute-center': 'absolute left-0 top-0 flex justify-center items-center wh-full',
|
||||||
'absolute-lt': 'absolute left-0 top-0',
|
'absolute-lt': 'absolute left-0 top-0',
|
||||||
'absolute-lb': 'absolute left-0 bottom-0',
|
'absolute-lb': 'absolute left-0 bottom-0',
|
||||||
'absolute-rt': 'absolute right-0 top-0',
|
'absolute-rt': 'absolute right-0 top-0',
|
||||||
'absolute-rb': 'absolute right-0 bottom-0',
|
'absolute-rb': 'absolute right-0 bottom-0',
|
||||||
'fixed-center': 'fixed left-0 top-0 flex justify-center items-center w-full h-full',
|
'fixed-center': 'fixed left-0 top-0 flex justify-center items-center wh-full',
|
||||||
'ellipsis-text': 'whitespace-nowrap overflow-hidden overflow-ellipsis',
|
'ellipsis-text': 'whitespace-nowrap overflow-hidden overflow-ellipsis',
|
||||||
'nowrap-hidden': 'whitespace-nowrap overflow-hidden'
|
'nowrap-hidden': 'whitespace-nowrap overflow-hidden'
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user