feat: gate upload access behind auth notice
This commit is contained in:
+12
-1
@@ -120,6 +120,12 @@ const router = createRouter({
|
||||
component: () => import('@/views/system/ForbiddenView.vue'),
|
||||
meta: { title: '无权访问', noindex: true },
|
||||
},
|
||||
{
|
||||
path: '/401',
|
||||
name: 'auth-required',
|
||||
component: () => import('@/views/system/AuthRequiredView.vue'),
|
||||
meta: { title: '需要登录', noindex: true },
|
||||
},
|
||||
{
|
||||
path: '/:pathMatch(.*)*',
|
||||
name: 'not-found',
|
||||
@@ -136,7 +142,12 @@ router.beforeEach((to, _from, next) => {
|
||||
const authStore = useAuthStore()
|
||||
|
||||
if (to.meta.requiresAuth && !authStore.isLoggedIn) {
|
||||
next({ name: 'login', query: { redirect: to.fullPath } })
|
||||
next({
|
||||
name: 'auth-required',
|
||||
query: {
|
||||
redirect: to.fullPath,
|
||||
},
|
||||
})
|
||||
} else if (to.meta.requiresAdmin && !authStore.isAdmin) {
|
||||
next({ name: 'forbidden' })
|
||||
} else if ((to.name === 'login' || to.name === 'register') && authStore.isLoggedIn) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import MiniLocationMap from '@/components/cloud/MiniLocationMap.vue'
|
||||
import QuickUploadModal from '@/components/cloud/QuickUploadModal.vue'
|
||||
import { supabase } from '@/lib/supabase'
|
||||
import { loadAMap } from '@/lib/amap'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { NIcon } from 'naive-ui'
|
||||
import { Adjustments, Calendar, CloudUpload, Refresh, Map, Satellite, X } from '@vicons/tabler'
|
||||
|
||||
@@ -24,6 +25,7 @@ interface CloudMarkerData {
|
||||
}
|
||||
|
||||
const mapEl = ref<HTMLDivElement>()
|
||||
const authStore = useAuthStore()
|
||||
const previewCloud = ref<CloudMarkerData | null>(null)
|
||||
const satelliteOn = ref(false)
|
||||
const statusText = ref('加载中...')
|
||||
@@ -70,7 +72,6 @@ const archiveTitle = computed(() => {
|
||||
if (mapMode.value === 'realtime') return '实时'
|
||||
return archiveKind.value === 'day' ? archiveDay.value : archiveMonth.value
|
||||
})
|
||||
|
||||
function getMinuteOfDay(date: Date) {
|
||||
return date.getHours() * 60 + date.getMinutes()
|
||||
}
|
||||
@@ -344,6 +345,7 @@ function toggleSat() {
|
||||
}
|
||||
|
||||
function openQuickUpload() {
|
||||
if (authStore.loading || !authStore.isLoggedIn) return
|
||||
quickUploadOpen.value = true
|
||||
}
|
||||
|
||||
@@ -446,9 +448,11 @@ onUnmounted(() => {
|
||||
<div class="absolute bottom-6 right-7 z-20 flex w-10 flex-col items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="w-10 h-10 bg-white rounded-lg shadow-md flex items-center justify-center hover:bg-gray-50"
|
||||
title="快速上传图片"
|
||||
class="w-10 h-10 rounded-lg shadow-md flex items-center justify-center"
|
||||
:class="authStore.loading || !authStore.isLoggedIn ? 'cursor-not-allowed bg-slate-100 text-slate-300 shadow-none' : 'bg-white hover:bg-gray-50'"
|
||||
:title="authStore.isLoggedIn ? '快速上传图片' : '请先登录后上传图片'"
|
||||
aria-label="快速上传图片"
|
||||
:disabled="authStore.loading || !authStore.isLoggedIn"
|
||||
@click="openQuickUpload"
|
||||
>
|
||||
<NIcon size="20" style="display: inline-flex; vertical-align: middle;">
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { NButton } from 'naive-ui'
|
||||
import { RouterLink, useRoute } from 'vue-router'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const redirect = computed(() => {
|
||||
const value = route.query.redirect
|
||||
return typeof value === 'string' && value.startsWith('/') ? value : '/'
|
||||
})
|
||||
|
||||
const title = computed(() => {
|
||||
if (redirect.value === '/upload') {
|
||||
return '上传前先登录'
|
||||
}
|
||||
|
||||
return '需要先登录'
|
||||
})
|
||||
|
||||
const description = computed(() => {
|
||||
if (redirect.value === '/upload') {
|
||||
return '上传云图、使用地图快捷上传都需要先登录账号。登录后再回来,这里的上传入口就会开放。'
|
||||
}
|
||||
|
||||
return '这个页面需要先登录才能继续访问。登录成功后可以返回刚才的目标页面继续操作。'
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex min-h-[calc(100vh-4rem)] items-center justify-center px-4 py-10">
|
||||
<div class="w-full max-w-2xl border border-slate-200 bg-white px-8 py-14 text-center shadow-sm">
|
||||
<div class="text-7xl leading-none">🔐</div>
|
||||
<p class="mt-6 text-sm font-medium uppercase tracking-[0.24em] text-sky-600">401 Login Required</p>
|
||||
<h1 class="mt-3 text-4xl font-bold text-slate-900">{{ title }}</h1>
|
||||
<p class="mx-auto mt-4 max-w-xl text-sm leading-7 text-slate-600">
|
||||
{{ description }}
|
||||
</p>
|
||||
|
||||
<div class="mt-8 flex flex-wrap items-center justify-center gap-3">
|
||||
<RouterLink :to="{ path: '/login', query: redirect !== '/' ? { redirect } : undefined }">
|
||||
<NButton type="default" secondary strong class="oc-panel-button oc-panel-button--sky">前往登录</NButton>
|
||||
</RouterLink>
|
||||
<RouterLink to="/">
|
||||
<NButton type="default" secondary strong class="oc-panel-button oc-panel-button--neutral">返回地图</NButton>
|
||||
</RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user