refactor(projects): 精简版+动态路由权限初步

This commit is contained in:
Soybean
2022-01-03 22:20:10 +08:00
parent 7a0648dba5
commit de2057f141
354 changed files with 2053 additions and 22117 deletions

View File

@@ -1,137 +0,0 @@
<template>
<n-grid :x-gap="16" :y-gap="16" :item-responsive="true" responsive="screen">
<n-grid-item span="s:24 m:8">
<n-card title="时间线" :bordered="false" class="rounded-16px shadow-sm">
<div class="h-360px">
<n-timeline>
<n-timeline-item v-for="item in timelines" :key="item.type" v-bind="item" />
</n-timeline>
</div>
</n-card>
</n-grid-item>
<n-grid-item span="s:24 m:16">
<n-card title="表格" :bordered="false" class="rounded-16px shadow-sm">
<div class="h-360px">
<n-data-table size="small" :columns="columns" :data="tableData" />
</div>
</n-card>
</n-grid-item>
</n-grid>
</template>
<script setup lang="ts">
import { h } from 'vue';
import { NGrid, NGridItem, NCard, NTimeline, NTimelineItem, NDataTable, NTag } from 'naive-ui';
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', 'programmer']
},
{
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>

View File

@@ -1,28 +0,0 @@
<template>
<div class="bg-gradient p-16px rounded-16px text-white">
<slot></slot>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
interface Props {
/** 渐变开始的颜色 */
startColor?: string;
/** 渐变结束的颜色 */
endColor?: string;
}
const props = withDefaults(defineProps<Props>(), {
startColor: '#56cdf3',
endColor: '#719de3'
});
const gradientStyle = computed(() => `linear-gradient(to bottom right, ${props.startColor}, ${props.endColor})`);
</script>
<style scoped>
.bg-gradient {
background-image: v-bind(gradientStyle);
}
</style>

View File

@@ -1,3 +0,0 @@
import GradientBg from './GradientBg.vue';
export { GradientBg };

View File

@@ -1,70 +0,0 @@
<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">
<gradient-bg class="h-100px" :start-color="item.colors[0]" :end-color="item.colors[1]">
<h3 class="text-16px">{{ item.title }}</h3>
<div class="flex justify-between pt-12px">
<Icon :icon="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>
</n-grid-item>
</n-grid>
</template>
<script setup lang="ts">
import { NGrid, NGridItem } from 'naive-ui';
import { Icon } from '@iconify/vue';
import { CountTo } from '@/components';
import { GradientBg } from './components';
interface CardData {
id: string;
title: string;
value: number;
unit: string;
colors: [string, string];
icon: string;
}
const cardData: CardData[] = [
{
id: 'visit',
title: '访问量',
value: 1000000,
unit: '',
colors: ['#ec4786', '#b955a4'],
icon: 'ant-design:bar-chart-outlined'
},
{
id: 'amount',
title: '成交额',
value: 234567.89,
unit: '$',
colors: ['#865ec0', '#5144b4'],
icon: 'ant-design:money-collect-outlined'
},
{
id: 'download',
title: '下载数',
value: 666666,
unit: '',
colors: ['#56cdf3', '#719de3'],
icon: 'carbon:document-download'
},
{
id: 'trade',
title: '成交数',
value: 999999,
unit: '',
colors: ['#fcbc25', '#f68057'],
icon: 'ant-design:trademark-circle-outlined'
}
];
</script>
<style scoped></style>

View File

@@ -1,152 +0,0 @@
[
{
"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
}
]

View File

@@ -1,129 +0,0 @@
<template>
<n-grid :x-gap="16" :y-gap="16" :item-responsive="true" responsive="screen">
<n-grid-item span="s:24 m:16">
<n-card :bordered="false" class="rounded-16px shadow-sm">
<div class="flex w-full h-360px">
<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 class="flex-1-hidden h-full">
<div ref="lineRef" class="wh-full"></div>
</div>
</div>
</n-card>
</n-grid-item>
<n-grid-item span="s:24 m:8">
<n-card :bordered="false" class="rounded-16px shadow-sm">
<div ref="pieRef" class="w-full h-360px"></div>
</n-card>
</n-grid-item>
</n-grid>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { NGrid, NGridItem, NCard, NButton } from 'naive-ui';
import { Line, Pie } from '@antv/g2plot';
import { 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: 'inner',
autoRotate: false,
formatter: ({ percent }) => `${(percent * 100).toFixed(0)}%`
},
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>

View File

@@ -1,5 +0,0 @@
import TopChart from './TopChart/index.vue';
import DataCard from './DataCard/index.vue';
import BottomPart from './BottomPart/index.vue';
export { TopChart, DataCard, BottomPart };

View File

@@ -1,13 +1,9 @@
<template>
<n-space :vertical="true" :size="16">
<top-chart />
<data-card />
<bottom-part />
</n-space>
<div>
<h3>DashboardAnalysis</h3>
<router-link to="/about">about</router-link>
</div>
</template>
<script lang="ts" setup>
import { NSpace } from 'naive-ui';
import { TopChart, DataCard, BottomPart } from './components';
</script>
<script setup lang="ts"></script>
<style scoped></style>

View File

@@ -1,4 +1,4 @@
import DashboardAnalysis from './analysis/index.vue';
import DashboardWorkbench from './workbench/index.vue';
const DashboardAnalysis = () => import('./analysis/index.vue');
const DashboardWorkbench = () => import('./workbench/index.vue');
export { DashboardAnalysis, DashboardWorkbench };

View File

@@ -1,48 +0,0 @@
<template>
<n-card :bordered="false" class="rounded-16px shadow-sm">
<div class="flex-y-center justify-between">
<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="24" :wrap="false">
<n-statistic v-for="item in statisticData" :key="item.id" class="whitespace-nowrap" v-bind="item"></n-statistic>
</n-space>
</div>
</n-card>
</template>
<script setup lang="ts">
import { NCard, NSpace, NStatistic } from 'naive-ui';
import { useAuthStore } from '@/store';
interface StatisticData {
id: number;
label: string;
value: string;
}
const auth = useAuthStore();
const statisticData: StatisticData[] = [
{
id: 0,
label: '项目数',
value: '25'
},
{
id: 1,
label: '待办',
value: '4/16'
},
{
id: 2,
label: '消息',
value: '12'
}
];
</script>
<style scoped></style>

View File

@@ -1,24 +0,0 @@
<template>
<div
class="flex-col-center p-12px border-1px border-[#efeff5] dark:border-[#ffffff17] rounded-4px hover:shadow-sm cursor-pointer"
>
<Icon :icon="icon" :style="{ color: iconColor }" class="text-30px" />
<p class="py-8px text-16px">{{ label }}</p>
</div>
</template>
<script setup lang="ts">
import { Icon } from '@iconify/vue';
interface Props {
/** 快捷操作名称 */
label: string;
/** 图标 */
icon: string;
/** 图标颜色 */
iconColor: string;
}
defineProps<Props>();
</script>
<style scoped></style>

View File

@@ -1,41 +0,0 @@
<template>
<div
class="p-4px border-1px border-[#efeff5] dark:border-[#ffffff17] rounded-4px hover:shadow-sm cursor-pointer"
@click="handleOpenSite"
>
<header class="flex-y-center">
<Icon :icon="icon" :style="{ color: iconColor }" class="text-30px" />
<h3 class="pl-12px text-18px font-semibold">{{ name }}</h3>
</header>
<p class="py-8px h-56px text-[#999]">{{ description }}</p>
<div class="flex justify-end">
<span>{{ author }}</span>
</div>
</div>
</template>
<script setup lang="ts">
import { Icon } from '@iconify/vue';
interface Props {
/** 技术名称 */
name: string;
/** 技术描述 */
description: string;
/** 技术作者 */
author: string;
/** 技术官网 */
site: string;
/** 技术图标 */
icon: string;
/** 图标颜色 */
iconColor?: string;
}
const props = defineProps<Props>();
function handleOpenSite() {
window.open(props.site, '_blank');
}
</script>
<style scoped></style>

View File

@@ -1,4 +0,0 @@
import TechnologyCard from './TechnologyCard.vue';
import ShortcutsCard from './ShortcutsCard.vue';
export { TechnologyCard, ShortcutsCard };

View File

@@ -1,152 +0,0 @@
<template>
<n-grid :item-responsive="true" responsive="screen" :x-gap="16" :y-gap="16">
<n-grid-item span="s:24 m:16">
<n-space :vertical="true" :size="16">
<n-card title="项目主要技术栈" :bordered="false" size="small" class="shadow-sm rounded-16px">
<template #header-extra>
<a class="text-primary" href="javascript:;">更多技术栈</a>
</template>
<n-grid :item-responsive="true" responsive="screen" cols="m:2 l:3" :x-gap="8" :y-gap="8">
<n-grid-item v-for="item in technology" :key="item.id">
<technology-card v-bind="item" />
</n-grid-item>
</n-grid>
</n-card>
<n-card title="动态" :bordered="false" size="small" class="shadow-sm rounded-16px">
<template #header-extra>
<a class="text-primary" href="javascript:;">更多动态</a>
</template>
<n-list>
<n-list-item v-for="item in activity" :key="item.id">
<template #prefix>
<div class="w-48px h-48px">
<img src="@/assets/svg/avatar/avatar01.svg" alt="" class="wh-full" />
</div>
</template>
<n-thing :title="item.content" :description="item.time" />
</n-list-item>
</n-list>
</n-card>
</n-space>
</n-grid-item>
<n-grid-item span="s:24 m:8">
<n-space :vertical="true" :size="16">
<n-card title="快捷操作" :bordered="false" size="small" class="shadow-sm rounded-16px">
<n-grid :item-responsive="true" responsive="screen" cols="m:2 l:3" :x-gap="8" :y-gap="8">
<n-grid-item v-for="item in shortcuts" :key="item.id">
<shortcuts-card v-bind="item" />
</n-grid-item>
</n-grid>
</n-card>
<n-card title="创意" :bordered="false" size="small" class="shadow-sm rounded-16px">
<n-carousel :autoplay="true" :show-arrow="true">
<banner-svg type="1" />
<banner-svg type="2" />
<banner-svg type="3" />
</n-carousel>
</n-card>
</n-space>
</n-grid-item>
</n-grid>
</template>
<script setup lang="ts">
import { NGrid, NGridItem, NSpace, NCard, NList, NListItem, NThing, NCarousel } from 'naive-ui';
import { BannerSvg } from '@/components';
import { TechnologyCard, ShortcutsCard } from './components';
interface Technology {
id: number;
name: string;
description: string;
author: string;
site: string;
icon: string;
iconColor?: string;
}
interface Activity {
id: number;
content: string;
time: string;
}
interface Shortcuts {
id: number;
label: string;
icon: string;
iconColor: string;
}
const technology: Technology[] = [
{
id: 0,
name: 'Vue',
description: '一套用于构建用户界面的渐进式框架',
author: '尤雨溪 - Evan You',
site: 'https://v3.cn.vuejs.org/',
icon: 'vscode-icons:file-type-vue'
},
{
id: 1,
name: 'TypeScript',
description: 'JavaScript类型的超集它可以编译成纯JavaScript',
author: '微软 - Microsoft',
site: 'https://www.typescriptlang.org/',
icon: 'vscode-icons:file-type-typescript-official'
},
{
id: 2,
name: 'Vite',
description: '下一代前端开发与构建工具',
author: '尤雨溪 - Evan You',
site: 'https://vitejs.cn/',
icon: 'vscode-icons:file-type-vite'
},
{
id: 3,
name: 'NaiveUI',
description: '一个 Vue 3 组件库',
author: '图森未来 - TuSimple',
site: 'https://www.naiveui.com/zh-CN/os-theme',
icon: 'mdi:alpha-n-box-outline',
iconColor: '#5fbc22'
},
{
id: 4,
name: 'WindiCSS',
description: '下一代实用优先的CSS框架',
author: 'Windicss',
site: 'https://windicss.org/',
icon: 'file-icons:windi',
iconColor: '#48b0f1'
},
{
id: 5,
name: 'Pinia',
description: 'vue状态管理框架支持vue2、vue3',
author: 'Posva',
site: 'https://pinia.esm.dev/',
icon: 'mdi:fruit-pineapple',
iconColor: '#fecf48'
}
];
const activity: Activity[] = [
{ id: 4, content: 'Soybean 刚才把工作台页面随便写了一些,凑合能看了!', time: '2021-11-07 22:45:32' },
{ id: 3, content: 'Soybean 正在忙于为soybean-admin写项目说明文档', time: '2021-11-03 20:33:31' },
{ id: 2, content: 'Soybean 准备为soybean-admin 1.0的发布做充分的准备工作!', time: '2021-10-31 22:43:12' },
{ id: 1, content: '@yanbowe 向soybean-admin提交了一个bug多标签栏不会自适应。', time: '2021-10-27 10:24:54' },
{ id: 0, content: 'Soybean 在2021年5月28日创建了开源项目soybean-admin', time: '2021-05-28 22:22:22' }
];
const shortcuts: Shortcuts[] = [
{ id: 0, label: '主控台', icon: 'mdi:desktop-mac-dashboard', iconColor: '#409eff' },
{ id: 1, label: '系统管理', icon: 'ic:outline-settings', iconColor: '#7238d1' },
{ id: 2, label: '权限管理', icon: 'mdi:family-tree', iconColor: '#f56c6c' },
{ id: 3, label: '组件', icon: 'fluent:app-store-24-filled', iconColor: '#19a2f1' },
{ id: 4, label: '表格', icon: 'mdi:table-large', iconColor: '#fab251' },
{ id: 5, label: '图表', icon: 'mdi:chart-areaspline', iconColor: '#8aca6b' }
];
</script>
<style scoped></style>

View File

@@ -1,4 +0,0 @@
import WorkbenchHeader from './WorkbenchHeader/index.vue';
import WorkbenchMain from './WorkbenchMain/index.vue';
export { WorkbenchHeader, WorkbenchMain };

View File

@@ -1,11 +1,6 @@
<template>
<n-space :vertical="true" :size="16">
<workbench-header />
<workbench-main />
</n-space>
<div>DashboardWorkbench</div>
</template>
<script lang="ts" setup>
import { NSpace } from 'naive-ui';
import { WorkbenchHeader, WorkbenchMain } from './components';
</script>
<script setup lang="ts"></script>
<style scoped></style>