mirror of
https://github.com/soybeanjs/soybean-admin.git
synced 2025-09-22 03:26:38 +08:00
refactor(projects): perf page home
This commit is contained in:
parent
123fd4f96c
commit
4c61c6ff3c
@ -1,251 +1,40 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, watch } from 'vue';
|
import { computed } from 'vue';
|
||||||
import { $t } from '@/locales';
|
|
||||||
import { useAppStore } from '@/store/modules/app';
|
import { useAppStore } from '@/store/modules/app';
|
||||||
import { useEcharts } from '@/hooks/chart/use-echarts';
|
import HeaderBanner from './modules/header-banner.vue';
|
||||||
import HeaderBanner from './components/header-banner.vue';
|
import CardData from './modules/card-data.vue';
|
||||||
import CardData from './components/card-data.vue';
|
import LineChart from './modules/line-chart.vue';
|
||||||
import ProjectNews from './components/project-news.vue';
|
import PieChart from './modules/pie-chart.vue';
|
||||||
|
import ProjectNews from './modules/project-news.vue';
|
||||||
|
import CreativityBanner from './modules/creativity-banner.vue';
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
|
|
||||||
const gap = computed(() => (appStore.isMobile ? 0 : 16));
|
const gap = computed(() => (appStore.isMobile ? 0 : 16));
|
||||||
|
|
||||||
const { domRef: lineRef, updateOptions: updateLineOptions } = useEcharts(() => ({
|
|
||||||
tooltip: {
|
|
||||||
trigger: 'axis',
|
|
||||||
axisPointer: {
|
|
||||||
type: 'cross',
|
|
||||||
label: {
|
|
||||||
backgroundColor: '#6a7985'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
data: [$t('page.home.downloadCount'), $t('page.home.registerCount')]
|
|
||||||
},
|
|
||||||
grid: {
|
|
||||||
left: '3%',
|
|
||||||
right: '4%',
|
|
||||||
bottom: '3%',
|
|
||||||
containLabel: true
|
|
||||||
},
|
|
||||||
xAxis: {
|
|
||||||
type: 'category',
|
|
||||||
boundaryGap: false,
|
|
||||||
data: [] as string[]
|
|
||||||
},
|
|
||||||
yAxis: {
|
|
||||||
type: 'value'
|
|
||||||
},
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
color: '#8e9dff',
|
|
||||||
name: $t('page.home.downloadCount'),
|
|
||||||
type: 'line',
|
|
||||||
smooth: true,
|
|
||||||
stack: 'Total',
|
|
||||||
areaStyle: {
|
|
||||||
color: {
|
|
||||||
type: 'linear',
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
x2: 0,
|
|
||||||
y2: 1,
|
|
||||||
colorStops: [
|
|
||||||
{
|
|
||||||
offset: 0.25,
|
|
||||||
color: '#8e9dff'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
offset: 1,
|
|
||||||
color: '#fff'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
emphasis: {
|
|
||||||
focus: 'series'
|
|
||||||
},
|
|
||||||
data: [] as number[]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
color: '#26deca',
|
|
||||||
name: $t('page.home.registerCount'),
|
|
||||||
type: 'line',
|
|
||||||
smooth: true,
|
|
||||||
stack: 'Total',
|
|
||||||
areaStyle: {
|
|
||||||
color: {
|
|
||||||
type: 'linear',
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
x2: 0,
|
|
||||||
y2: 1,
|
|
||||||
colorStops: [
|
|
||||||
{
|
|
||||||
offset: 0.25,
|
|
||||||
color: '#26deca'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
offset: 1,
|
|
||||||
color: '#fff'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
emphasis: {
|
|
||||||
focus: 'series'
|
|
||||||
},
|
|
||||||
data: []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}));
|
|
||||||
|
|
||||||
async function mockLineData() {
|
|
||||||
await new Promise(resolve => {
|
|
||||||
setTimeout(resolve, 1000);
|
|
||||||
});
|
|
||||||
|
|
||||||
updateLineOptions(opts => {
|
|
||||||
opts.xAxis.data = ['06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00', '24:00'];
|
|
||||||
opts.series[0].data = [4623, 6145, 6268, 6411, 1890, 4251, 2978, 3880, 3606, 4311];
|
|
||||||
opts.series[1].data = [2208, 2016, 2916, 4512, 8281, 2008, 1963, 2367, 2956, 678];
|
|
||||||
|
|
||||||
return opts;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateLineLocale() {
|
|
||||||
updateLineOptions((opts, factory) => {
|
|
||||||
const originOpts = factory();
|
|
||||||
|
|
||||||
opts.legend.data = originOpts.legend.data;
|
|
||||||
opts.series[0].name = originOpts.series[0].name;
|
|
||||||
opts.series[1].name = originOpts.series[1].name;
|
|
||||||
|
|
||||||
return opts;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const { domRef: pieRef, updateOptions: updatePieOptions } = useEcharts(() => ({
|
|
||||||
tooltip: {
|
|
||||||
trigger: 'item'
|
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
bottom: '1%',
|
|
||||||
left: 'center',
|
|
||||||
itemStyle: {
|
|
||||||
borderWidth: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
color: ['#5da8ff', '#8e9dff', '#fedc69', '#26deca'],
|
|
||||||
name: $t('page.home.schedule'),
|
|
||||||
type: 'pie',
|
|
||||||
radius: ['45%', '75%'],
|
|
||||||
avoidLabelOverlap: false,
|
|
||||||
itemStyle: {
|
|
||||||
borderRadius: 10,
|
|
||||||
borderColor: '#fff',
|
|
||||||
borderWidth: 1
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
show: false,
|
|
||||||
position: 'center'
|
|
||||||
},
|
|
||||||
emphasis: {
|
|
||||||
label: {
|
|
||||||
show: true,
|
|
||||||
fontSize: '12'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
labelLine: {
|
|
||||||
show: false
|
|
||||||
},
|
|
||||||
data: [] as { name: string; value: number }[]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}));
|
|
||||||
|
|
||||||
async function mockPieData() {
|
|
||||||
await new Promise(resolve => {
|
|
||||||
setTimeout(resolve, 1000);
|
|
||||||
});
|
|
||||||
|
|
||||||
updatePieOptions(opts => {
|
|
||||||
opts.series[0].data = [
|
|
||||||
{ name: $t('page.home.study'), value: 20 },
|
|
||||||
{ name: $t('page.home.entertainment'), value: 10 },
|
|
||||||
{ name: $t('page.home.work'), value: 40 },
|
|
||||||
{ name: $t('page.home.rest'), value: 30 }
|
|
||||||
];
|
|
||||||
|
|
||||||
return opts;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function updatePieLocale() {
|
|
||||||
updatePieOptions((opts, factory) => {
|
|
||||||
const originOpts = factory();
|
|
||||||
|
|
||||||
opts.series[0].name = originOpts.series[0].name;
|
|
||||||
|
|
||||||
opts.series[0].data = [
|
|
||||||
{ name: $t('page.home.study'), value: 20 },
|
|
||||||
{ name: $t('page.home.entertainment'), value: 10 },
|
|
||||||
{ name: $t('page.home.work'), value: 40 },
|
|
||||||
{ name: $t('page.home.rest'), value: 30 }
|
|
||||||
];
|
|
||||||
|
|
||||||
return opts;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function init() {
|
|
||||||
mockLineData();
|
|
||||||
mockPieData();
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => appStore.locale,
|
|
||||||
() => {
|
|
||||||
updateLineLocale();
|
|
||||||
updatePieLocale();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// init
|
|
||||||
init();
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NSpace vertical :size="16">
|
<NSpace vertical :size="16">
|
||||||
<HeaderBanner />
|
<HeaderBanner />
|
||||||
|
<CardData />
|
||||||
<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:14">
|
<NGi span="24 s:24 m:14">
|
||||||
<NCard :bordered="false" class="card-wrapper">
|
<NCard :bordered="false" class="card-wrapper">
|
||||||
<div ref="lineRef" class="h-360px overflow-hidden"></div>
|
<LineChart />
|
||||||
</NCard>
|
</NCard>
|
||||||
</NGi>
|
</NGi>
|
||||||
<NGi span="24 s:24 m:10">
|
<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>
|
<PieChart />
|
||||||
</NCard>
|
</NCard>
|
||||||
</NGi>
|
</NGi>
|
||||||
</NGrid>
|
</NGrid>
|
||||||
<CardData />
|
|
||||||
<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:14">
|
<NGi span="24 s:24 m:14">
|
||||||
<ProjectNews />
|
<ProjectNews />
|
||||||
</NGi>
|
</NGi>
|
||||||
<NGi span="24 s:24 m:10">
|
<NGi span="24 s:24 m:10">
|
||||||
<NCard :title="$t('page.home.creativity')" :bordered="false" size="small" class="card-wrapper h-full">
|
<CreativityBanner />
|
||||||
<div class="flex-center h-full">
|
|
||||||
<IconLocalBanner class="text-400px sm:text-320px text-primary" />
|
|
||||||
</div>
|
|
||||||
</NCard>
|
|
||||||
</NGi>
|
</NGi>
|
||||||
</NGrid>
|
</NGrid>
|
||||||
</NSpace>
|
</NSpace>
|
||||||
|
17
src/views/home/modules/creativity-banner.vue
Normal file
17
src/views/home/modules/creativity-banner.vue
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { $t } from '@/locales';
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'CreativityBanner'
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<NCard :title="$t('page.home.creativity')" :bordered="false" size="small" class="card-wrapper h-full">
|
||||||
|
<div class="flex-center h-full">
|
||||||
|
<IconLocalBanner class="text-400px sm:text-320px text-primary" />
|
||||||
|
</div>
|
||||||
|
</NCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
151
src/views/home/modules/line-chart.vue
Normal file
151
src/views/home/modules/line-chart.vue
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { watch } from 'vue';
|
||||||
|
import { $t } from '@/locales';
|
||||||
|
import { useAppStore } from '@/store/modules/app';
|
||||||
|
import { useEcharts } from '@/hooks/chart/use-echarts';
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'LineChart'
|
||||||
|
});
|
||||||
|
|
||||||
|
const appStore = useAppStore();
|
||||||
|
|
||||||
|
const { domRef, updateOptions } = useEcharts(() => ({
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'cross',
|
||||||
|
label: {
|
||||||
|
backgroundColor: '#6a7985'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: [$t('page.home.downloadCount'), $t('page.home.registerCount')]
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '3%',
|
||||||
|
right: '4%',
|
||||||
|
bottom: '3%',
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
data: [] as string[]
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value'
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
color: '#8e9dff',
|
||||||
|
name: $t('page.home.downloadCount'),
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
stack: 'Total',
|
||||||
|
areaStyle: {
|
||||||
|
color: {
|
||||||
|
type: 'linear',
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
x2: 0,
|
||||||
|
y2: 1,
|
||||||
|
colorStops: [
|
||||||
|
{
|
||||||
|
offset: 0.25,
|
||||||
|
color: '#8e9dff'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: 1,
|
||||||
|
color: '#fff'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
focus: 'series'
|
||||||
|
},
|
||||||
|
data: [] as number[]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
color: '#26deca',
|
||||||
|
name: $t('page.home.registerCount'),
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
stack: 'Total',
|
||||||
|
areaStyle: {
|
||||||
|
color: {
|
||||||
|
type: 'linear',
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
x2: 0,
|
||||||
|
y2: 1,
|
||||||
|
colorStops: [
|
||||||
|
{
|
||||||
|
offset: 0.25,
|
||||||
|
color: '#26deca'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: 1,
|
||||||
|
color: '#fff'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
focus: 'series'
|
||||||
|
},
|
||||||
|
data: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
|
||||||
|
async function mockData() {
|
||||||
|
await new Promise(resolve => {
|
||||||
|
setTimeout(resolve, 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
updateOptions(opts => {
|
||||||
|
opts.xAxis.data = ['06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00', '24:00'];
|
||||||
|
opts.series[0].data = [4623, 6145, 6268, 6411, 1890, 4251, 2978, 3880, 3606, 4311];
|
||||||
|
opts.series[1].data = [2208, 2016, 2916, 4512, 8281, 2008, 1963, 2367, 2956, 678];
|
||||||
|
|
||||||
|
return opts;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateLocale() {
|
||||||
|
updateOptions((opts, factory) => {
|
||||||
|
const originOpts = factory();
|
||||||
|
|
||||||
|
opts.legend.data = originOpts.legend.data;
|
||||||
|
opts.series[0].name = originOpts.series[0].name;
|
||||||
|
opts.series[1].name = originOpts.series[1].name;
|
||||||
|
|
||||||
|
return opts;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function init() {
|
||||||
|
mockData();
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => appStore.locale,
|
||||||
|
() => {
|
||||||
|
updateLocale();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// init
|
||||||
|
init();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<NCard :bordered="false" class="card-wrapper">
|
||||||
|
<div ref="domRef" class="h-360px overflow-hidden"></div>
|
||||||
|
</NCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
109
src/views/home/modules/pie-chart.vue
Normal file
109
src/views/home/modules/pie-chart.vue
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { watch } from 'vue';
|
||||||
|
import { $t } from '@/locales';
|
||||||
|
import { useAppStore } from '@/store/modules/app';
|
||||||
|
import { useEcharts } from '@/hooks/chart/use-echarts';
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'PieChart'
|
||||||
|
});
|
||||||
|
|
||||||
|
const appStore = useAppStore();
|
||||||
|
|
||||||
|
const { domRef, updateOptions } = useEcharts(() => ({
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'item'
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
bottom: '1%',
|
||||||
|
left: 'center',
|
||||||
|
itemStyle: {
|
||||||
|
borderWidth: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
color: ['#5da8ff', '#8e9dff', '#fedc69', '#26deca'],
|
||||||
|
name: $t('page.home.schedule'),
|
||||||
|
type: 'pie',
|
||||||
|
radius: ['45%', '75%'],
|
||||||
|
avoidLabelOverlap: false,
|
||||||
|
itemStyle: {
|
||||||
|
borderRadius: 10,
|
||||||
|
borderColor: '#fff',
|
||||||
|
borderWidth: 1
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
show: false,
|
||||||
|
position: 'center'
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
fontSize: '12'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
labelLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
data: [] as { name: string; value: number }[]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
|
||||||
|
async function mockData() {
|
||||||
|
await new Promise(resolve => {
|
||||||
|
setTimeout(resolve, 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
updateOptions(opts => {
|
||||||
|
opts.series[0].data = [
|
||||||
|
{ name: $t('page.home.study'), value: 20 },
|
||||||
|
{ name: $t('page.home.entertainment'), value: 10 },
|
||||||
|
{ name: $t('page.home.work'), value: 40 },
|
||||||
|
{ name: $t('page.home.rest'), value: 30 }
|
||||||
|
];
|
||||||
|
|
||||||
|
return opts;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateLocale() {
|
||||||
|
updateOptions((opts, factory) => {
|
||||||
|
const originOpts = factory();
|
||||||
|
|
||||||
|
opts.series[0].name = originOpts.series[0].name;
|
||||||
|
|
||||||
|
opts.series[0].data = [
|
||||||
|
{ name: $t('page.home.study'), value: 20 },
|
||||||
|
{ name: $t('page.home.entertainment'), value: 10 },
|
||||||
|
{ name: $t('page.home.work'), value: 40 },
|
||||||
|
{ name: $t('page.home.rest'), value: 30 }
|
||||||
|
];
|
||||||
|
|
||||||
|
return opts;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function init() {
|
||||||
|
mockData();
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => appStore.locale,
|
||||||
|
() => {
|
||||||
|
updateLocale();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// init
|
||||||
|
init();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<NCard :bordered="false" class="card-wrapper">
|
||||||
|
<div ref="domRef" class="h-360px overflow-hidden"></div>
|
||||||
|
</NCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
Loading…
Reference in New Issue
Block a user