feat: 登录显示加载遮罩并将统计面板图表改为异步加载
- 登录请求期间显示全屏遮罩与「正在登录」提示,并等待路由跳转完成再隐藏 - 统计面板 echarts 改为 defineAsyncComponent 按需加载,避免阻塞登录后首屏
This commit is contained in:
@@ -56,6 +56,7 @@ export default {
|
||||
submit: { zh: '登录', en: 'Sign In', ja: 'ログイン' },
|
||||
toRegister: { zh: '没有账号?去注册', en: "Don't have an account? Sign up", ja: 'アカウントをお持ちでない方は新規登録' },
|
||||
fillRequired: { zh: '请填写用户名和密码', en: 'Please enter username and password', ja: 'ユーザー名とパスワードを入力してください' },
|
||||
loggingIn: { zh: '正在登录,请稍候…', en: 'Signing in, please wait…', ja: 'ログイン中です。少々お待ちください…' },
|
||||
success: { zh: '登录成功', en: 'Signed in successfully', ja: 'ログインしました' },
|
||||
failed: { zh: '登录失败', en: 'Sign in failed', ja: 'ログインに失敗しました' },
|
||||
},
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
// 统计面板组件:展示指定时间范围的收支汇总、概览指标、趋势、分类占比与交易渠道分布
|
||||
import { ref, computed, onMounted, watch, nextTick, unref } from 'vue'
|
||||
import { ref, computed, onMounted, watch, nextTick, unref, defineAsyncComponent } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { NCard, NGrid, NGridItem, NStatistic, NSpace, NSelect, NDatePicker, NInput, NInputNumber, NButton, NAutoComplete, NModal, NAlert, NDropdown, NIcon, useMessage } from 'naive-ui'
|
||||
import { SparklesOutline, BulbOutline } from '@vicons/ionicons5'
|
||||
import VChart from 'vue-echarts'
|
||||
import { use } from 'echarts/core'
|
||||
import { CanvasRenderer } from 'echarts/renderers'
|
||||
import { LineChart, PieChart, BarChart } from 'echarts/charts'
|
||||
import { TitleComponent, TooltipComponent, LegendComponent, GridComponent } from 'echarts/components'
|
||||
import { getStatisticsSummary, getStatisticsGroup } from '../api/statistics'
|
||||
import { getCategoryList } from '../api/category'
|
||||
import { getTagList } from '../api/tag'
|
||||
@@ -20,8 +15,28 @@ import { useKeywordHistory } from '../composables/useKeywordHistory'
|
||||
import { getChannelLabel } from '../utils/channel'
|
||||
import { renderCategoryLabel } from '../utils/render'
|
||||
|
||||
// 注册 ECharts 所需组件
|
||||
use([CanvasRenderer, LineChart, PieChart, BarChart, TitleComponent, TooltipComponent, LegendComponent, GridComponent])
|
||||
// 图表组件异步加载:echarts 体积较大,登录后进入面板时先渲染页面骨架,
|
||||
// echarts 在后台按需下载并注册,避免阻塞目标页首屏
|
||||
const VChart = defineAsyncComponent(async () => {
|
||||
const [vueEcharts, echartsCore, renderers, charts, components] = await Promise.all([
|
||||
import('vue-echarts'),
|
||||
import('echarts/core'),
|
||||
import('echarts/renderers'),
|
||||
import('echarts/charts'),
|
||||
import('echarts/components'),
|
||||
])
|
||||
echartsCore.use([
|
||||
renderers.CanvasRenderer,
|
||||
charts.LineChart,
|
||||
charts.PieChart,
|
||||
charts.BarChart,
|
||||
components.TitleComponent,
|
||||
components.TooltipComponent,
|
||||
components.LegendComponent,
|
||||
components.GridComponent,
|
||||
])
|
||||
return vueEcharts.default
|
||||
})
|
||||
|
||||
const { t, locale } = useI18n() // 国际化
|
||||
const message = useMessage() // 消息提示
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useMessage, NCard, NForm, NFormItem, NInput, NButton, NSpace } from 'naive-ui'
|
||||
import { useMessage, NCard, NForm, NFormItem, NInput, NButton, NSpace, NSpin } from 'naive-ui'
|
||||
import { login } from '../api/user'
|
||||
import { useUserStore } from '../store/user'
|
||||
import { useRegistrationStore } from '../store/registration'
|
||||
@@ -54,7 +54,8 @@ async function handleLogin() {
|
||||
userStore.setToken(res.data.token) // 保存 token
|
||||
userStore.setUserInfo(res.data.user.nickname, res.data.user.id) // 保存用户信息
|
||||
message.success(t('login.success'))
|
||||
router.push(resolveRedirect()) // 跳转到来源页或统计面板
|
||||
// 等待目标页加载完成再隐藏遮罩,避免跳转过程中的空白等待
|
||||
await router.push(resolveRedirect()) // 跳转到来源页或统计面板
|
||||
} catch (e: any) {
|
||||
message.error(e.message || t('login.failed'))
|
||||
} finally {
|
||||
@@ -82,6 +83,11 @@ async function handleLogin() {
|
||||
</NSpace>
|
||||
</NForm>
|
||||
</NCard>
|
||||
<!-- 登录中遮罩:登录请求已发起,提示用户等待,同时覆盖跳转过程中的加载 -->
|
||||
<div v-if="loading" class="login-loading">
|
||||
<NSpin size="large" stroke="#ffffff" />
|
||||
<span class="login-loading__text">{{ t('login.loggingIn') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -93,4 +99,24 @@ async function handleLogin() {
|
||||
height: 100vh;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
}
|
||||
|
||||
/* 登录中遮罩:覆盖整个视口,居中显示加载动画与提示文案 */
|
||||
.login-loading {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
background: rgba(0, 0, 0, 0.35);
|
||||
backdrop-filter: blur(2px);
|
||||
}
|
||||
|
||||
.login-loading__text {
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user